C++——构造函数
构造函数是 C++ 中最重要的特殊成员函数之一,它在创建对象时自动调用,用于初始化对象的状态。本文将全面介绍 C++ 构造函数的各个方面,包括基本概念、类型、语法、特殊用法以及最佳实践。
一、构造函数的基本概念
1. 定义与作用
构造函数是与类同名的特殊成员函数,在对象创建时自动调用,主要作用包括:
- 初始化对象成员变量
- 分配资源(如内存、文件句柄等)
- 执行必要的设置操作
2. 构造函数的特点
- 名称必须与类名相同
- 没有返回类型(连
void
也不能声明) - 可以重载(一个类可以有多个构造函数)
- 编译器自动生成默认构造函数(如果用户没有定义任何构造函数)
二、构造函数的类型
1. 默认构造函数
没有参数或所有参数都有默认值的构造函数:
class MyClass {
public:// 无参默认构造函数MyClass() {std::cout << "Default constructor called" << std::endl;}// 带默认参数的构造函数MyClass(int x = 0, double y = 0.0) : valX(x), valY(y) {std::cout << "Parameterized constructor with defaults called" << std::endl;}
private:int valX;double valY;
};
2. 参数化构造函数
接受参数用于初始化对象的构造函数:
class Point {
public:Point(int x, int y) : xCoord(x), yCoord(y) {std::cout << "Point created at (" << xCoord << ", " << yCoord << ")" << std::endl;}
private:int xCoord;int yCoord;
};
3. 拷贝构造函数
拷贝构造函数的典型声明如下:
class MyClass {
public:MyClass(const MyClass& other);
};
其中, other 是对同类型对象的引用,通常是常量引用。
使用同类型另一个对象初始化新对象的特殊构造函数:
class String {
public:// 普通构造函数String(const char* str = "") {size = strlen(str);data = new char[size + 1];strcpy(data, str);}// 拷贝构造函数String(const String& other) {std::cout << "Copy constructor called" << std::endl;size = other.size;data = new char[size + 1];strcpy(data, other.data);}~String() {delete[] data;}
private:char* data;size_t size;
};
4. 移动构造函数 (C++11)
通过"窃取"临时对象的资源来构造新对象,避免不必要的拷贝:
class ResourceHolder {
public:// 移动构造函数ResourceHolder(ResourceHolder&& other) noexcept : resource(other.resource), data(other.data) {other.resource = nullptr;other.data = nullptr;std::cout << "Move constructor called" << std::endl;}// 其他成员...
private:int* resource;char* data;
};
三、构造函数的语法详解
1. 基本语法
class ClassName {
public:// 构造函数声明ClassName(); // 默认构造函数ClassName(Type1 param1, Type2 param2, ...); // 参数化构造函数// 成员初始化列表语法ClassName(Type1 param1, Type2 param2) : member1(param1), member2(param2) {// 构造函数体}
};
2. 成员初始化列表
- 在构造函数体执行前初始化成员变量
- 比在构造函数体内赋值更高效(特别是对于类类型成员和
const
成员) - 必须使用成员初始化列表的情况:
const
成员变量- 引用成员变量
- 没有默认构造函数的类类型成员
class MemberInitExample {
private:const int constMember;int& refMember;std::string strMember;
public:// 必须使用成员初始化列表MemberInitExample(int val, int& ref, const char* str) : constMember(val), refMember(ref), strMember(str) {// constMember = val; // 错误:不能给const成员赋值// refMember = ref; // 错误:引用必须在初始化时绑定}
};
3. 委托构造函数 (C++11)
一个构造函数可以调用同一个类的另一个构造函数:
class Rectangle {
private:int width, height;
public:// 主构造函数Rectangle(int w, int h) : width(w), height(h) {}// 委托构造函数Rectangle(int size) : Rectangle(size, size) {} // 调用主构造函数// 另一个委托构造函数Rectangle() : Rectangle(1, 1) {} // 调用size构造函数
};
四、构造函数的最佳实践
1. 初始化策略
- 优先使用成员初始化列表:特别是对于类类型成员和
const
成员 - 避免在构造函数体中进行不必要的赋值
- 保持初始化顺序一致:成员初始化列表的顺序应与成员声明顺序一致
2. 异常安全
- 构造函数可能抛出异常,确保资源不会泄漏
- 使用 RAII(资源获取即初始化)原则管理资源
- 对于可能抛出异常的构造函数,考虑使用智能指针