存在类的层次结构,例如,
Base -> A -> B
。
每当调用
A::A()
时,实际要构造的对象可能是 A
类中的任何一个,然后它是最后一个被调用的 ctor;或者属于 B
类,然后 B::B()
稍后会被调用。是否可以区分这些情况并检测当前调用的构造函数是否属于实际正在构造的类型?
令人信服的解决方案是使用
typeid
:
A::A() {
if (typeid(this) == typeid(A*)) {
// A is the actual type of the object being constructed
}
}
但是,
typeid
(以及 vtable)在构造函数和析构函数中的工作方式不同,并且不公开最终类,而是返回有关当前(静态)类本身的信息。这是因为层次结构中更深层的类的构造函数尚未被调用,因此从已构造的父类访问它们是非法的。请参阅“说明”部分的最后一段,网址为 cppreference。
我不需要知道正在构造的对象的确切类型,只需要检测当前构造函数是否是最终构造函数。可以做到吗?
我可以修改
Base
类的主体以及所有其他类的构造函数。 A
和B
的身体不受我控制。
C++20 就可以了。
编辑:我将尝试详细说明哪些代码可以修改,哪些不能修改。
首先,我拥有
Base
的完全访问权限。它始终是层次结构的基类。
然后库的用户可以像这样定义后代类:
class A : public Base
{
REGISTER(A);
// some user code
};
class B : public A
{
REGISTER(B);
// some other user code
};
REGISTER
宏由库提供。特别是,它定义了特定类型的构造函数(这就是我控制它的方式)。如果用户定义了其他构造函数,则行为是未定义的,因此我们可以假设我们的构造函数是唯一的。请注意,我们不知道碱基的名称,因此我们无法从 A
显式调用 B
的 ctor;此外,可能有多个基地,甚至是虚拟的。
我正在寻找的技巧将被放入
REGISTER
宏中。
感谢大家参与讨论!我们根据@Phil1970的评论提出了解决方案
虚拟基可以做到这一点,因为只有最派生的类才会调用它。
简短的建议引导我们找到了一个出色的解决方案。我们可以通过在层次结构中的每个构造函数中传递当前的 typeid 来调用虚拟继承基类的构造函数。构造实例时,基构造函数将仅在最底层的派生类中执行。最后,在每个构造函数中,我们只检查当前类的 typeid 是否与传递给虚拟基类的 typeid 相同。详情请参阅godbolt。
对于@Phil1970:如果您使用这些详细信息单独回答,我们将接受它。