Hi all,
I’ve been translating a C# program to C++/CLI and I saw something that I thought It might or introduce unpredicted results to my code.
A virtual method was called from inside a base class.
That was enough motivation for me to debug the code, and actually find out that it was the virtual method of the derived class which was actually called from the constructor of the base class!
During this debugging session though, I also discovered that the constructor of the base class is called AFTER any initialization of the member variables of the derived class!
I’ve searched for some info for constructing objects in .NET, and I only found this in my first attempts.
Do not call virtual members on an object inside its constructors.
Calling a virtual member causes the most-derived override to be called regardless of whether the constructor for the type that defines the most-derived override has been called. The following code example demonstrates this issue. As the base class constructor executes, it calls the derived class member, even though the derived class constructor has not been called. This example prints BadBaseClass
to show that the state field has not been updated by the DerivedFromBad
constructor.
At first I stopped reading after I glanced at the headline, because it was clear this was the rule I knew.
Unfortunately the rest of it says that what I saw was correct behavior.
So it is reasonable, If virtual table has to be setup, to prepare derived class before base class.
But this is not valid C++ as far as I know.
The following C++/CLI program produces this call sequence
UtilityItem::UtilityItem(long)
BaseClass::BaseClass()
DerivedClass::TestVirtual()
DerivedClass::DerivedClass() //inside constructor
DerivedClass::TestVirtual()
Instead of this call sequence.
BaseClass::BaseClass()
BaseClass::TestVirtual()
UtilityItem::UtilityItem(long)
DerivedClass::DerivedClass() //inside constructor
DerivedClass::TestVirtual()
Where can I find such information Because It is not easily spotted in “What's New in Visual C++ Compiler, Language, and Tools” help section
Thank you
Ioannis
ref class UtilityItem
{
public:
UtilityItem(long initU)
{
u = initU;
}
private:
long u;
};
ref class BaseClass
{
public:
BaseClass() :
i(-1)
{
d = 1.2;
TestVirtual();
}
private:
long i;
double d;
public:
long intVal()
{
return i;
}
double dblVal()
{
return d;
}
public:
virtual long TestVirtual()
{
return -234;
}
};
ref class DerivedClass : BaseClass
{
public:
DerivedClass() :
ui(gcnew UtilityItem(15)),
ii(-2)
{
dd = 2.3;
TestVirtual();
}
private:
long ii;
double dd;
UtilityItem^ ui;
public:
long intValD()
{
return ii;
}
double dblValD()
{
return dd;
}
public:
virtual long TestVirtual() override
{
return -234;
}
};
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
DerivedClass dd;
long i = dd.intValD();
return 0;
}