这些是我的班级定义:
class Foo{
int _ent;
public:
void printEnt() const{cout << _ent << ' ';}
};
class Bar{
Foo _foo;
public:
void printEnt() const{_foo.printEnt();}
};
这是我的测试代码:
char* buf = new char[sizeof(Foo) + sizeof(Foo) + sizeof(Bar)];
fill(buf, buf + sizeof(Foo) + sizeof(Foo) + sizeof(Bar), 'J');
cout << ((int*)buf)[0] << ' ' << ((int*)buf)[1] << ' ' << ((int*)buf)[2] << endl;
Foo* first = new (buf) Foo;
Foo* second = new (buf + sizeof(Foo)) Foo();
Bar* third = new (buf + sizeof(Foo) * 2) Bar;
first->printEnt(); second->printEnt(); third->printEnt();
我的输出是:
1246382666 1246382666 1246382666
1246382666 0 1246382666
但如果我将public
默认ctor添加到Foo
:Foo() : _ent(0) {}
我的输出变为:
1246382666 1246382666 1246382666
0 0 0
这是正确的行为吗?添加我自己的默认ctor是否应该删除默认初始化的可能性?
如果重要的话,我在gcc 4.8.1上运行此代码。结果应该是可靠的,因为我在调试和断言中运行:assert(sizeof(Foo) == sizeof(int) && sizeof(Bar) == sizeof(int));
答案 0 :(得分:3)
一旦为类型提供构造函数,它将永远是
调用,用于默认初始化和值
初始化。这是该语言的基本原则。
因此,一旦定义Foo::Foo()
,就会随时调用它
构造一个Foo
;如果有默认构造函数,它将是
即使在默认初始化的情况下也会调用。所以
你看到的行为是正确的。
编辑:
默认初始化解释§8.5/ 7,特别是:
默认初始化T类型的对象意味着:
- 如果T是(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(12.1) [...]
在你的情况下,你可能也想看看如何 如果没有提供,编译器会生成默认构造函数, §12.1/ 4;特别是生成的默认构造函数 调用任何基类或成员的默认构造函数。
值初始化在§8.5/ 8中。它基本上是默认的 初始化之前是零初始化,因此默认 没有做任何事情的初始化仍会找到所有内容 零初始化。
然而,更根本的是:在这种情况下,非常根本 涉及C ++的原则,可以追溯到很久以前 standard:如果为对象提供构造函数,则将 使用。没有做各种奇怪的指针演员,它 如果没有正确的话,就不可能得到一个物体 建造。该标准描述了这种情况的发生和覆盖 很多其他特殊情况,但基本原则已经 从一开始(以及任何会导致它的提案) 在标准中受到尊重必将失败)。答案 1 :(得分:1)
您的问题已在标准的C ++ 11修订版中得到解答:
class Foo{
int _ent=0;
public:
// ...
};
如果您随后定义了自己的默认构造函数,则该成员仍将初始化为其默认值,即使您的默认构造函数未明确执行此操作。
答案 2 :(得分:0)
当您提供默认构造函数时,您不再获得编译器生成的构造函数。由于您的默认构造函数将成员初始化为0,因此成员将始终为0,这尤其正确,因为该成员是私有的,您无法更改它。