了解基类初始化

时间:2015-06-14 04:41:32

标签: c++ base

考虑该计划:

#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

斯科特迈耶斯在他的Effective C++中所说的是:

  

在派生类对象的基类构造期间,类型为   对象是基类的对象。

所以,我期望打印base,因为我们在调用foo函数时处于基类类构造之下。我错过了什么?也许是UB?如果是,请指出相关部分。

3 个答案:

答案 0 :(得分:3)

Scott意味着当你在基类构造函数中时,通常的虚函数规则不起作用。因此,如果您在基类构造函数中,那么在ctor中调用的任何虚函数(该基类)将在当前正在构建的对象上调用。

所以你的代码打印出正确的结果:在foo()的ctor中调用B而不是在父构造函数中。如果您在foo ctor中调用了A ,则会base打印出来。

根据标准,行为仍被视为未定义:

  

[12.6.2 / 13] 可以为正在构建的对象调用成员函数(包括虚拟成员函数,10.3)。类似地,正在构造的对象可以是typeid运算符的操作数   (5.2.8)或动态演员(5.2.7)。 但是,如果这些操作   在ctor-initializer(或直接调用的函数)中执行   或者在所有mem-initializers之前间接地从ctor-initializer)   对于基类已经完成,操作的结果是   未定义

但你应该明白,“undefined”在这里意味着你可以在被调用的函数中使用一些内部状态。既然你不这样做会一致,但标准仍然认为它是未定义的。 “未定义”部分与打印的内容无关,而是与成员函数中可能访问的内容无关。

答案 1 :(得分:1)

不要在构造函数中使用虚函数 - 第9项

答案 2 :(得分:0)

Scott Mayers所说的是对的,但你的计划是错误的。

#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

这句话绝对错误:

在派生类构造函数初始化列表中,首先应在初始化派生类成员对象之前调用基类构造函数。在实例化对象之前,您无法调用非静态成员函数。

    String dateTime= "2015-12-10T14:00:00";
    SimpleDateFormat frm1 = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss");
    Date date = frm1.parse(dateTime);
    SimpleDateFormat frm2 = new SimpleDateFormat("dd/MM/YYYY");
    String date1 = frm2.format(date);
    System.err.println(date1);
    SimpleDateFormat frm3 = new SimpleDateFormat("HH:mm");
    String time = frm3.format(date);
    System.err.println(time);