目录
- 1. 默认构造函数(Default Constructor)
- 2. 参数化构造函数(Parameterized Constructor)
- 3. 拷贝构造函数(Copy Constructor)
- 4. 移动构造函数(Move Constructor)(C++11 起)
- 5. 委托构造函数(Delegating Constructor)(C++11 起)
- 6. 继承构造函数(Inheriting Constructor)(C++11 起)
- 7. 转换构造函数(Conversion Constructor)
- 总结
- 注意事项
默认构造函数
初始化构造函数(有参数)
拷贝构造函数
移动构造函数(move和右值引用)
委托构造函数
C++11引入了委托构造的概念,使得构造函数可以在同一个类的一个构造函数调用另一个构造安徽念书,从而达到简化代码的目的
class Base { public: int val1; int val2; Base() { val1 = 1; } Base(int value) : Base() { // 委托Base() 构造函数 val2 = value; } }; int main() { Base b(2); std::cout << b.val1 << std::endl; std::cout << b.val2 << std::endl; }转换构造函数
默认构造函数和初始化构造函数在定义类的对象,完成对象的初始化工作
复制构造函数用于复制本类的对象
转换构造函数用于将其他类型的变量,隐式转换为本类对象
class Student { public: int age; int num; public: Student() { // 默认构造函数 this->age = 20; this->num = 100; } Student(int a, int n) : age(a), num(n){ //初始化构造函数,有参数和参数列表 }; Student(const Student& s){ //拷贝构造函数,这里与编译器生成的一致 this->age = s.age; this->num = s.num; }; Student(int r){ //转换构造函数,形参是其他类型变量,且只有一个形参 this->age = r; this->num = 1002; }; ~Student(){} }; int main() { Student s1; Student s2(18,1001); int a = 10; Student s3(a); Student s4(s3); printf("s1 age:%d, num:%d\n", s1.age, s1.num); printf("s2 age:%d, num:%d\n", s2.age, s2.num); printf("s3 age:%d, num:%d\n", s3.age, s3.num); printf("s4 age:%d, num:%d\n", s4.age, s4.num); return 0; //运行结果 //s1 age:20, num:1000 //s2 age:18, num:1001 //s3 age:10, num:1002 //s2 age:10, num:1002 } +继承构造
在传统C++中,构造函数如果需要继承是需要将参数一一传递的,C++11利用using关键字引入了继承构造函数的概念
class Base { public: int val1; int val2; Base() { val1 = 1; } Base(int value) : Base() { // 委托Base() 构造函数 val2 = value; } }; class SubClass : public Base { public: using Base::Base; // 继承构造 }; int main() { SubClass s(2); std::cout << s.val1 << std::endl; std::cout << s.val2 << std::endl; }
在 C++ 中,构造函数(Constructor)是用于初始化对象的特殊成员函数。根据其功能和使用场景,构造函数可以分为多种类型。以下是详细的分类和说明:
1. 默认构造函数(Default Constructor)
- 定义:没有参数,或所有参数都有默认值的构造函数。
- 作用:创建对象时不需要显式提供参数。
- 触发场景:
- 声明对象时没有提供参数:
MyClass obj; - 数组或容器中元素的默认初始化。
- 声明对象时没有提供参数:
- 注意:
- 如果用户没有定义任何构造函数,编译器会自动生成一个隐式的默认构造函数。
- 如果用户定义了其他构造函数(如带参数的构造函数),编译器不再生成隐式默认构造函数,此时若需要默认构造函数,必须显式声明。
class MyClass {
public:
// 默认构造函数
MyClass() {
// 初始化代码
}
};
2. 参数化构造函数(Parameterized Constructor)
- 定义:接受一个或多个参数的构造函数。
- 作用:根据传入的参数初始化对象。
- 示例:
class Point {
private:
int x, y;
public:
// 参数化构造函数
Point(int a, int b) : x(a), y(b) {} // 初始化列表
};
3. 拷贝构造函数(Copy Constructor)
- 定义:接受同类型对象的常量引用作为参数的构造函数。
- 作用:用另一个对象的值初始化新对象。
- 触发场景:
- 对象通过值传递或返回。
- 显式拷贝初始化:
MyClass obj2 = obj1;
- 注意:
- 如果用户未定义拷贝构造函数,编译器会自动生成一个隐式的拷贝构造函数(浅拷贝)。
- 如果类管理动态内存或其他资源,必须手动实现深拷贝。
class MyClass {
public:
// 拷贝构造函数
MyClass(const MyClass& other) {
// 深拷贝逻辑
}
};
4. 移动构造函数(Move Constructor)(C++11 起)
- 定义:接受同类型对象的右值引用(
&&)作为参数的构造函数。 - 作用:通过“窃取”资源(如动态内存)来高效初始化对象,避免深拷贝。
- 触发场景:
- 使用
std::move转移资源。 - 返回临时对象时。
- 使用
- 注意:
- 移动构造函数通常标记为
noexcept,以支持标准库容器的优化。
- 移动构造函数通常标记为
class MyClass {
public:
// 移动构造函数
MyClass(MyClass&& other) noexcept {
// 窃取 other 的资源,并将其置为无效状态
}
};
5. 委托构造函数(Delegating Constructor)(C++11 起)
- 定义:一个构造函数可以调用同一个类中的其他构造函数。
- 作用:避免重复代码,提高复用性。
- 示例:
class MyClass {
public:
// 委托构造函数
MyClass() : MyClass(0, 0) {} // 委托给下面的构造函数
// 参数化构造函数
MyClass(int a, int b) : x(a), y(b) {}
};
6. 继承构造函数(Inheriting Constructor)(C++11 起)
- 定义:派生类可以直接继承基类的构造函数。
- 语法:使用
using Base::Base;。 - 作用:简化派生类的构造函数定义。
class Base {
public:
Base(int x) { /* ... */ }
};
class Derived : public Base {
public:
using Base::Base; // 继承基类的构造函数
};
7. 转换构造函数(Conversion Constructor)
- 定义:接受单个参数的构造函数(可以定义隐式类型转换)。
- 注意:
- 若需禁止隐式转换,需用
explicit关键字标记。
- 若需禁止隐式转换,需用
class MyClass {
public:
// 转换构造函数(允许隐式转换)
MyClass(int x) { /* ... */ }
// 显式构造函数(禁止隐式转换)
explicit MyClass(double d) { /* ... */ }
};
总结
| 构造函数类型 | 关键特性 | 应用场景 |
|---|---|---|
| 默认构造函数 | 无参数 | 对象默认初始化 |
| 参数化构造函数 | 接受参数 | 根据输入初始化对象 |
| 拷贝构造函数 | 接受常量引用 | 对象拷贝(深拷贝/浅拷贝) |
| 移动构造函数 | 接受右值引用(C++11) | 高效转移资源 |
| 委托构造函数 | 调用同类其他构造函数(C++11) | 代码复用 |
| 继承构造函数 | 使用 using 继承基类构造函数(C++11) |
简化派生类构造逻辑 |
| 转换构造函数 | 单参数构造函数(可能允许隐式转换) | 类型转换 |
注意事项
explicit** 关键字**:禁止隐式类型转换,防止意外的构造函数调用。- Rule of Three/Five:
- 如果定义了拷贝构造函数、拷贝赋值运算符或析构函数,通常需要同时定义其他相关函数(如移动构造函数、移动赋值运算符)。
- 编译器生成的函数:
- 若未手动定义,编译器会自动生成默认构造函数、拷贝构造函数、移动构造函数等,但可能不符合需求(如浅拷贝)。
通过合理使用这些构造函数类型,可以高效管理对象的生命周期和资源!
No comments yet.