[英]Understanding base class initialization
考虑该计划:
#include<iostream>
#include<vector>
struct A
{
int a;
A(int) { }
virtual int foo(){ std::cout << "base" << std::endl; return 5; }
};
struct B : A
{
int b;
B(): b(9), A(foo()) { }
virtual int foo(){ std::cout << "derived" << std::endl; return 6; }
};
B b; //prints derived
int main(){ }
Scott Meyers在他的Effective C++
所说的是:
在派生类对象的基类构造期间,对象的类型是基类的类型。
所以,我希望base
要代为印刷的,因为我们是在基类的类建筑在调用foo
功能。 我错过了什么? 也许是UB? 如果是,请指出相关部分。
Scott意味着当你在基类构造函数中时,通常的虚函数规则不起作用。 因此,如果您在基类构造函数中,那么在ctor中调用的任何虚函数(该基类)将在当前正在构建的对象上调用。
所以你的代码打印出正确的结果:在B
的ctor中调用foo()
而不是父构造函数。 如果你叫foo
里面 A
构造函数,你将不得不base
打印。
根据标准,行为仍被视为未定义:
[12.6.2 / 13]可以为正在建造的对象调用成员函数(包括虚拟成员函数,10.3)。 类似地,正在构造的对象可以是typeid运算符(5.2.8)或dynamic_-cast(5.2.7)的操作数。 但是,如果在基类的所有mem-initializer完成之前,在ctor-initializer(或直接或间接从ctor-initializer中调用的函数)中执行这些操作,则操作的结果是未定义的 。
但是你应该明白,“undefined”在这里意味着你可以在被调用的函数中使用一些内部状态。 既然你不这样做会一致,但标准仍然认为它是未定义的。 “未定义”部分与打印的内容无关,而是与成员函数中可能访问的内容无关。
只是不要在构造函数中使用虚函数 - 第9项
Scott Mayers所说的是对的,但你的计划是错误的。
B(): b(9), A(foo()) { }
这句话绝对错误:
在派生类构造函数初始化列表中,首先应在初始化派生类成员对象之前调用基类构造函数。 在实例化对象之前,您无法调用非静态成员函数。
#include<iostream>
#include<vector>
struct A
{
int a;
A(int) { std::cout<<"base constructed\n"; }
virtual int foo(){ std::cout << "base" << std::endl; return 5; }
};
struct B : A
{
int b;
B(): A(6), b(9) { std::cout<<"derived constructed"; }
virtual int foo(){ std::cout << "derived" << std::endl; return 6; }
};
int main(){
B b; //prints derived
}
O/P
base constructed
derived constructed
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.