关于using声明结合虚继承的构造函数调用疑问
关于继承构造函数与虚基类初始化的问题
我在查阅cppreference中关于using声明的内容时,在“继承构造函数”章节看到如下代码:
struct V { V() = default; V(int); }; struct Q { Q() = default; }; struct A : virtual V, Q { using V::V; A() = delete; }; int bar() { return 42; } struct B : A { B() : A(bar()) {} // OK }; struct C : B {}; int main() { C c; // “bar” is not invoked, because the V subobject // is not initialized as part of B // (the V subobject is initialized as part of C, // because “c” is the most derived object) }
根据注释,由于C是最派生对象,V子对象由C初始化,因此bar()不会被调用。移除C的定义后代码变为:
struct V { V() = default; V(int); }; struct Q { Q() = default; }; struct A : virtual V, Q { using V::V; A() = delete; }; int bar() { return 42; } struct B : A { B() : A(bar()) {} // OK }; int main() { B b; }
此时B是最派生对象,而A(int)构造函数是继承自V的虚基类构造函数,为什么bar()仍然不会被调用?
回答
核心原因是虚基类的初始化只能由最派生类全权负责,中间基类试图初始化虚基类的操作会被编译器直接忽略。
具体到这段代码里:
- B作为最派生类,它的构造函数里写的
: A(bar()),看似是调用A继承的V(int)构造函数,但这个继承的构造函数本质是用来初始化虚基类V的。 - 按照C++规则,只有最派生类才有资格初始化虚基类,中间基类(这里的A)对虚基类的初始化请求会被跳过。所以B的构造函数没有显式初始化V时,编译器会自动调用V的默认构造函数
V(),而A(bar())里的bar()根本不会被执行——因为编译器直接忽略了这个试图让A初始化虚基类的调用,连参数表达式都不会去求值。
简单说就是:继承的虚基类构造函数,只有最派生类调用它时才会触发虚基类的初始化;中间类调用的话,不仅不会初始化虚基类,连传入的参数表达式都不会执行。
内容的提问来源于stack exchange,提问作者rodman10
相关产品推荐
相关产品推荐

