On 1/27/18 12:01 PM, Jonathan M Davis wrote:
On Saturday, January 27, 2018 16:18:26 Thomas Mader via Digitalmars-d wrote:
On Saturday, 27 January 2018 at 14:48:08 UTC, Johan Engelen wrote:
I'm working on devirtualization and for that it's crucial to
know some spec details (or define them in the spec if they
aren't yet).

Currently, calling non-final member functions in the destructor
is allowed and these indirect calls are to the possibly
overridden functions of derived classes. That is, inside a base
class constructor, the object's type is its final type (so
possibly of a derived class). This is the same in the
destructor. Thus, the object's dynamic type does not change
during its lifetime.

Can't answer your question but have a little question.
How is the behavior different to the situation in C++? They argue
that it's not good to call virtual methods in Con-/Destructors in
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-ctor-virtu
al

So I guess it should better be not used in D as well?

D solved that problem. In C++, when you're in the base class constructor,
the object doesn't have its derived type yet. It's still just the base
class. Each class level gets add as it's constructed (the same in reverse
with the destructor). You don't have a full object until all constructors
have been run, and once you start running destructors, you don't have a full
class anymore either.

In D, on the other hand, the object is initialized with its init value
_before_ any constructors are run. So, it's a full object with a full type,
and everything virtual is going to get the type right.

Well, a virtual function may expect that the ctor has been run, and expect that members are different from their init values.

However, because you can initialize that data before calling the superclass' constructor, you can alleviate this problem as well.

For instance, the invariant may be called when you call the virtual function:

import std.stdio;

class A
{
    this() { writeln("A.ctor"); foo(); }
    void foo() { writeln("A.foo"); }
}

class B : A
{
    int x;
    this() {
        writeln("B.ctor");
        x = 1; // note the intialization before calling the base class
        super();
    }
    invariant {
        writeln("invariant!");
        assert(x == 1);
    }
    override void foo() { writeln("B.foo"); }
}

void main()
{
    auto b = new B;
}

output:
B.ctor
A.ctor
invariant! <- before calling foo
B.foo
invariant! <- after calling foo
invariant! <- after constructors are done

-Steve

Reply via email to