Class constructor

Top  Previous  Next

What is translated > Types > Records, Classes, Interfaces > Class > Constructors > Class constructor

In Delphi, besides instance constructors, there is a class constructor that runs once per type before the first use of that type, after all involved unit initialization sections. “Use” includes creating an instance, accessing a class member, or querying RTTI. A base type’s class constructor runs before the derived type’s class constructor.

 

A Delphi class constructor is declared as:

 

class constructor Create;

 

C++ has no direct notion of Delphi’s class constructor, and adding a second “static constructor” with the same name as the instance constructor would be ambiguous. Therefore, we translate it to a static function named ClassCreate, invoked through a one-time initializer.

 
:

class MyType

{

public:

    static void EnsureClassInitialized();

 

protected:

    static void ClassCreate();

    static void RegisterAtExit(); // optional: for a Delphi-like class destructor

 

private:

    static std::once_flag m_initFlag;

};

 

 

// MyType.cpp

#include "Mytype.h"

 

std::once_flag MyType::m_initFlag;

 

void MyType::EnsureClassInitialized()

{

    std::call_once(m_initFlag, []()

    {

        ClassCreate();

        RegisterAtExit();

    });

}

 

void MyType::ClassCreate()

{

    // One-time setup; mirrors Delphi "class constructor"

    ...

}

 

 

At every public entry point (instance constructors, static methods, and getters for translated “class vars”), call EnsureClassInitialized(). This reproduces Delphi’s “executed before first use” guarantee, and it’s thread-safe thanks to std::call_once.

 

std::call_once(flag, fn) ensures fn is executed exactly once across all threads for the given flag.
All concurrent callers block until the first successful execution completes; subsequent calls become no-ops.
If fn throws, the once state is not set, so a later call will attempt fn again.
Successful completion establishes a happens-before relationship for subsequent callers (they see the initialized state).

 

 

Inheritance

 

Delphi’s base-first order is mimicked by calling the base type’s initializer from the derived type’s initializer:

 

class Base {

public:

    static void EnsureClassInitialized();

protected:

    static void ClassCreate();

private:

    static std::once_flag m_init;

};

 

class Derived : public Base {

public:

    static void EnsureClassInitialized();

protected:

    static void ClassCreate();

private:

    static std::once_flag m_init;

};

 

// Impl

std::once_flag Base::m_init;

std::once_flag Derived::m_init;

 

void Base::EnsureClassInitialized()

{

    call_once(m_init, &Base::ClassCreate);

}

 

void Derived::EnsureClassInitialized()

{

    // Delphi: base class class-ctor runs first

    Base::EnsureClassInitialized();

    call_once(m_init, &Derived::ClassCreate);

}

 

So Base::EnsureClassInitialized() is called at the beginning of Derived::EnsureClassInitialized() before Derived::ClassCreate() runs.

 

 

 

 



This page belongs to the Delphi2Cpp Documentation

Delphi2Cpp home  Content