Thread overview
C++ base constructor call vs. D's
Oct 02, 2019
Just Dave
Oct 02, 2019
kinke
Oct 02, 2019
Jonathan M Davis
October 02, 2019
I was reading the C++ to D page, and came across this little bit about when to call the base class constructor:

"It's superior to C++ in that the base constructor call can be flexibly placed anywhere in the derived constructor."

Isn't there some inherent danger of not calling the base constructor first? Wouldn't C++'s method actually be equal in the effect that you could just overwrite whatever value the base class set in the derived class?



October 02, 2019
On Wednesday, 2 October 2019 at 17:22:40 UTC, Just Dave wrote:
> I was reading the C++ to D page, and came across this little bit about when to call the base class constructor:
>
>
> Isn't there some inherent danger of not calling the base constructor first?

The object's fields are pre-initialized before invoking the constructor, and not undefined as in C++, so probably not really dangerous.

> "It's superior to C++ in that the base constructor call can be flexibly placed anywhere in the derived constructor."

That formulation is s bit suboptimal, as the emphasis should be on '*can* be flexibly placed anywhere' - if you don't specify an explicit `super()` call, it's implicitly inserted at the beginning of the derived ctor, so a base ctor is always invoked at some time when constructing a derived object.
I don't think there are lots of use cases for deferring the super call, but it might be useful for logging purposes and such.
October 02, 2019
On Wednesday, October 2, 2019 11:22:40 AM MDT Just Dave via Digitalmars-d- learn wrote:
> I was reading the C++ to D page, and came across this little bit about when to call the base class constructor:
>
> "It's superior to C++ in that the base constructor call can be flexibly placed anywhere in the derived constructor."
>
> Isn't there some inherent danger of not calling the base constructor first? Wouldn't C++'s method actually be equal in the effect that you could just overwrite whatever value the base class set in the derived class?

The key difference in D has to do with init values. With a struct, the values that its members are directly initialized with create its init value. So,

struct S
{
    string s = "hello";
    int i;
    int j = 42;
}

results in

assert(S.init == S(s, 0, 42));

For classes, because the type system always treats them as references, the init value is null. So

class C
{
    string s = "hello";
    int i;
    int j = 42;
}

results in

assert(C.init is null);

However, the class still has the equivalent of the struct's init value - you just can't access it directly, and it's not used for default initialization, just in construction. So, before a class' constructor is run, its memory is initialized with that hidden init value, meaning that you don't have garbage when you enter the constructor, and the class is already fully formed in terms of its type and virtual table before any constructors are called, whereas in C++, if you're in a base class constructor, that class object is not yet the derived class type. So, it's actually possible and safe to call virtual functions from within a class constructor in D, whereas it isn't in C++. So, this example prints "D"

class C
{
    string foo()
    {
        return "C";
    }

    this()
    {
        import std.stdio;
        writeln(foo());
    }
}

class D : C
{
    override string foo()
    {
        return "D";
    }
}

void main()
{
    auto d = new D;
}

whereas C++ equivalent would likely blow up in your face.

- Jonathan M Davis