繁体   English   中英

了解基类初始化

[英]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(){ }

DEMO

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM