我明白了POD的含义,并且我知道当我在 C++ 中将结构声明为
struct f {};
有一个默认构造函数、一个默认复制构造函数、一个默认析构函数等。(如果我理解正确的话)
我的问题是:如何在没有隐式构造函数/析构函数/等的情况下仅使用普通数据(如 4 个 int 值)声明 POD 结构。
我错过了什么?
每个对象类型都有一个构造函数——否则你将如何构造它?——还有一个析构函数——否则它会如何被销毁?它们不会“妨碍”任何事情,因为在仅 POD 字段的情况下,默认实现是无操作的,就像您说的那样:
struct f {
f() {}
~f() {}
int a, b, c, d;
};
但是,如果您编写一个空的构造函数,则该类型将变为非 POD。C++11 通过默认解决了这个问题:
f() = default;
~f() = default;
复制构造函数的情况略有不同,其中隐式生成的构造函数只是为 POD 类型做“正确的事情”的一种便利:
f(const f& other) : a(other.a), b(other.b), c(other.c), d(other.d) {}
没有理由自己重写。如果要使类型不可复制,可以将复制构造函数标记为已删除f(const f&) = delete;
或声明它private
。
同样重要的是要注意成员函数不像成员变量那样存储在对象上。您可以将 aclass
或struct
同时视为两件事:
数据布局的描述
包含用于操作该数据的函数和类型的命名空间
面向对象编程的 C++ 模型只是将这两件事结合在一个地方。
如何在没有隐式构造函数/析构函数/等的情况下使用纯数据(如 4 个 int 值)声明 POD 结构。
像这样:
struct f {
int i1, i2, i3, i4;
};
编译器生成的构造函数不会妨碍它成为 POD。
10) POD struct 109是一个非联合类,它既是普通类又是标准布局类,并且没有非 POD 结构、非 POD 联合(或此类类型的数组)类型的非静态数据成员)。类似地,POD 联合是一个既是普通类又是标准布局类的联合,并且没有非 POD 结构、非 POD 联合(或此类类型的数组)类型的非静态数据成员。POD 类是一个 POD 结构或 POD 联合的类。
所以,它必须是
a) 普通类和
b) 标准布局类。
如下所述:
7) 标准布局类是这样的类:
— 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
— 没有虚函数 (10.3) 和虚基类(10.1),
——对所有非静态数据成员具有相同的访问控制(第 11 条),
——没有非标准布局的基类,
——要么在最派生类中没有非静态数据成员,要么在大多数具有
非静态数据成员的基类,或者没有具有非静态数据成员的基类,并且
- 没有与第一个非静态数据成员相同类型的基类。
和
6) [...] 普通类是具有普通默认构造函数 (12.1) 并且可轻松复制的类
详述于:
5) [...]如果默认构造函数不是用户提供的,并且如果:
- 它的类没有虚拟函数 (10.3) 和虚拟基类 (10.1),并且
- 没有非静态数据成员它的类有一个大括号或相等初始化器,并且
——它的类的所有直接基类都有普通的默认构造函数,并且
——对于它的类的所有非静态数据成员,它们是类类型(或其数组) ,每个这样的类都有一个简单的默认构造函数。
由于上述所有条件均适用,因此该类是 POD。
首先,所有这些隐式成员函数仅在概念上存在。在您实际尝试使用它们之前,它们不会真正影响任何东西。这意味着,如果您不希望他们这样做,他们不应该“妨碍”。
其次,非虚成员函数(无论是否显式声明)对类的数据布局没有影响。即他们在这方面没有“妨碍”(如果这就是你的意思)。
是的,POD 的定义明确排除了隐式生成的特殊成员函数。如果您指定其中之一与默认生成的完全相同:您的类型不再是 POD。在 C++11 中,这个问题是用default
关键字解决的。
有了这一切,POD 的定义(通常)与 C 代码中的定义相同:
struct X { int a, b, c, d; };