There is a hierarchy of classes, say, Base -> A -> B
.
Whenever A::A()
is called, the actual to-be-constructed object may be either of class A
, and then it is the last ctor called; or of class B
, and then B::B()
will be called later. Is it possible to distinguish between these cases and detect whether the constructor currently being called belongs to the type that is actually being constructed?
The compelling solution is to use typeid
:
A::A() {
if (typeid(this) == typeid(A*)) {
// A is the actual type of the object being constructed
}
}
However, typeid
(as well as vtables) works differently in constructors and destructors and do not expose the final class, instead returning the information about the current (static) class itself. This is due to that the constructors of classes deeper in the hierarchy hadn't been called yet and thus it would be illegal to access them from an already constructed parent. See the last paragraph in the Explanation section at cppreference.
I do not need to know the exact type of the object being constructed but only need to detect whether the current constructor is the final one. Is it possible to do it?
I can modify the body of a Base
class and the constructors of all other classes. Bodies of A
and B
are out of my control.
C++20 will be fine.
Edit: I'll try to elaborate which pieces of code I can modify and which cannot.
First of all, I have the full access to Base
. It is always the very base class of the hierarchy.
Then the users of the library may define descendant classes like this:
class A : public Base
{
REGISTER(A);
// some user code
};
class B : public A
{
REGISTER(B);
// some other user code
};
The REGISTER
macro is provided by the library. In particular, it defines the constructor of a specific type (that's how I can control it). If the user defines other constructors, the behavior is undefined, so we can assume that our constructor is the only one. Note that we do not know the bases' names so we cannot explicitly call A
's ctor from B
; furthermore, there may be multiple bases, even virtual ones.
The trick that I'm looking for will be placed into the REGISTER
macro.
Thank you all for taking part in discussion! We've come up with solution based on comment of @Phil1970
thing that a virtual base could do the trick as only the most derived class would call it.
The brief advice guided us to an excellent solution. We can invoke the constructor of special virtually inherited base class by passing current typeid in every constructor within our hierarchy. Special base class will store provided typeid. Upon constructing an instance, the call of base constructor will be executed only in the most derived class. And finally in every constructor we just check whether current class typeid is the same as passed to virtual base. See details in godbolt.
For @Phil1970: if you make separate answer with these details we'll make it accepted.