考虑该计划:
#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(){ }
斯科特迈耶斯在他的Effective C++
中所说的是:
在派生类对象的基类构造期间,类型为 对象是基类的对象。
所以,我期望打印base
,因为我们在调用foo
函数时处于基类类构造之下。我错过了什么?也许是UB?如果是,请指出相关部分。
答案 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);