$ 8.5 / 7 表明
- 如果T是一个(可能是cv限定的)非联合类类型而没有用户提供的构造函数,那么该对象 是零初始化,如果T的隐式声明的默认构造函数是非平凡的,那么构造函数是 调用。
我无法理解这句话的最后一部分“如果T的隐式声明的默认构造函数是非平凡的,那么构造函数就被调用了。”
有人可以用一个例子解释一下吗?
class A
{
int x;
};
class B : A {};
B b{};
我认为上面代码中的B
有一个非平凡的构造函数。但是,我如何观察对B
隐式声明的构造函数的调用,并确保我的编译器正在调用它?
答案 0 :(得分:6)
我认为上面代码中的B有一个非平凡的构造函数。
在您的示例中,构造函数很简单。
查看C ++ 11 12.1 / 5中的条件,两个类都没有用户声明的构造函数,虚函数,虚基类,具有初始化的成员或类类型的成员; A
没有基类,B
只有一个简单的基类。
但是我如何观察对B的隐式声明的构造函数的调用,并确保我的编译器正在调用它?
使用隐式但非平凡的默认构造函数创建类的一种方法是使用一个非平凡的成员或基类:
struct A {
// A user-declared constructor is non-trivial
A() {std::cout << "Construct A\n";}
};
struct B : A {};
现在,您可以(间接)观察被调用的B
的隐式构造函数,方法是在调用A
的构造函数时观察副作用。
答案 1 :(得分:2)
如果函数是用户声明的而非显式的,则用户提供该函数 在第一份声明中默认或删除。
因此,由于您没有为B
声明默认构造函数,因此不是用户提供的。
以下适用:
如果默认构造函数不是用户提供的,并且如果:
,则默认构造函数是微不足道的- 它的类没有虚函数(10.3),也没有虚拟基础 类(10.1)和
- 没有类的非静态数据成员 brace-or-equal-initializer 和
- 其类的所有直接基类都具有普通的默认值 构造函数,
- 对于类的所有非静态数据成员 类型(或其数组),每个这样的类都有一个普通的默认值 构造
所以它确实是微不足道的,因为我们可以递归地为A
应用相同的过程。
struct A { A() = default; }; // Trivial default constructor!
struct A { A() = delete; }; // Also trivial!
struct A { A(); }; // Can't be trivial!
struct B { virtual void f(); }
struct A : B {}; // Non-trivial default constructor.
struct B {};
struct A : virtual B {}; // Non-trivial default constructor.
答案 2 :(得分:0)
想象一下你有这个
struct A {
string a;
int value;
};
int main() {
A a = A();
return a.value;
}
当我们返回该值时, a.value
为零,因为该对象是零初始化的。但这还不够,因为a
还包含一个具有构造函数的字符串成员。对于要调用的构造函数,标准安排调用A
的构造函数,这最终将导致构造成员。