构造函数语义
合成默认构造函数的生成情况
1. 类没有任何构造函数
- 描述:该类没有定义任何构造函数。
- 示例:
class MBTX { // 没有任何构造函数 };
2. 包含类类型的成员变量
- 描述:类中包含一个类类型的成员变量,而该成员所属的类有默认构造函数。
- 示例:
class MATX { public: MATX() {} // 默认构造函数 }; class MBTX { public: MATX ma; // 包含 MATX 类型的成员变量 };
3. 子类继承父类的默认构造函数
- 描述:父类有默认构造函数,而子类没有任何构造函数。
- 示例:
class Parent { public: Parent() {} // 默认构造函数 }; class Child : public Parent { // 没有任何构造函数 };
4. 类含有虚函数
- 描述:类中含有虚函数,但没有定义任何构造函数。
- 示例:
class Base { public: virtual void func() {} }; class Derived : public Base { // 没有任何构造函数 };
5. 带有虚基类
- 描述:类中包含虚基类,且没有定义构造函数。
- 示例:
class VirtualBase { public: VirtualBase() {} }; class Derived : virtual public VirtualBase { // 没有任何构造函数 };
6. 成员变量赋初值
- 描述:在定义成员变量时直接赋初值,编译器仍然会生成合成默认构造函数。
- 示例:
class Time { public: int Second{0}; // 成员变量赋初值 };
7. 成员变量使用类类型且没有自定义构造函数
- 描述:如果类中包含一个类类型的成员变量,而该成员所属的类没有自定义构造函数(即只有合成的默认构造函数),那么编译器会生成合成默认构造函数。
- 示例:
class Member { public: Member() {} // 合成默认构造函数 }; class Container { public: Member m; // 成员变量 m 使用 Member 类型 };
8. 使用聚合初始化
- 描述:如果类是一个聚合(即没有用户定义的构造函数、没有私有或保护的非静态数据成员、没有基类),则可以使用聚合初始化。
- 示例:
class Point { public: int x, y; // 没有构造函数,符合聚合的条件 }; Point p{1, 2}; // 聚合初始化
9. 继承自没有构造函数的父类
- 描述:如果一个类继承自一个没有构造函数的父类,且没有定义构造函数,则合成默认构造函数会被生成。
- 示例:
class Base { // 没有构造函数 }; class Derived : public Base { // 没有任何构造函数 };
10. 使用 = default
显式声明
- 描述:可以显式声明一个默认构造函数为
default
,这不会影响合成默认构造函数的生成。 - 示例:
class Example { public: Example() = default; // 显式声明默认构造函数 };
合成默认构造函数不生成的情况
1. 有用户定义的构造函数
- 描述:如果类中定义了任何用户自定义的构造函数,则不会生成合成默认构造函数。
- 示例:
class MyClass { public: MyClass(int) {} // 用户定义的构造函数 };
2. 成员变量没有默认构造函数
- 描述:如果类中包含的成员变量没有默认构造函数,合成默认构造函数不会生成。
- 示例:
class NonDefault { public: NonDefault(int) {} // 没有默认构造函数 }; class MyClass { public: NonDefault nd; // 无法合成默认构造函数 };
3. 继承自没有默认构造函数的父类
- 描述:如果父类没有默认构造函数,子类也没有定义构造函数,则合成默认构造函数不会生成。
- 示例:
class Parent { public: Parent(int) {} // 没有默认构造函数 }; class Child : public Parent { // 没有任何构造函数 };
总结
合成默认构造函数在 C++ 中是一个强大的特性,允许开发者在不显式定义构造函数的情况下,依然能够创建对象。了解其生成和不生成的条件,对于设计类和对象的初始化过程至关重要。通过合理使用合成默认构造函数,可以提高代码的可读性和维护性,同时减少潜在的错误。