构造函数用于对象的创建,不同场景可能需要不同的初始化参数。
class MyClass {
public:
MyClass() { /* 默认初始化 */ } // 无参构造函数
MyClass(int x) { /* 用x初始化 */ } // 单参数构造函数
MyClass(int x, double y) { /* 复杂初始化 */ } // 双参数构造函数
};
语法上:构造函数与类名相同且无返回值,但允许参数列表不同。
C++标准规定析构函数必须无参数且唯一。
析构函数在对象销毁时由编译器自动调用,且无参数。若允许重载,编译器无法确定应调用哪个版本。析构函数的核心职责是释放资源(如内存、文件句柄等),通常需要统一的清理逻辑。若需差异化处理,应通过成员变量状态控制,而非重载
class FileHandler {
private:
bool isOpen = false;
public:
~FileHandler() {
if (isOpen) fclose(filePtr); // 根据状态统一处理
}
};
对象尚未完全构造
虚函数的调用通过对象的虚指针(vptr)和虚表(vtable)实现动态绑定。
在构造函数执行时,对象的虚指针尚未初始化(仅在基类构造函数完成后才指向派生类的虚表)。
设计逻辑冲突
构造函数从基类到派生类依次执行。
若基类构造为虚函数,派生类可能会尝试调用自身版本的构造函数(此时派生类对象尚未完全构造),导致逻辑混乱。
语言规范限制
C++标准明确规定构造函数不能声明为virtual
,编译器会直接报错
必须声明为虚函数的场景:通过基类指针删除派生类对象时
class Base {
public:
virtual ~Base() { cout << "Base destructor" << endl; } // 虚析构函数
};
class Derived : public Base {
private:
int* data;
public:
Derived() { data = new int[10]; }
~Derived() override {
delete[] data; // 派生类资源清理
cout << "Derived destructor" << endl;
}
};
// 使用基类指针创建和删除派生类对象
Base* ptr = new Derived();
delete ptr; // 若Base析构非虚,则仅调用Base::~Base(),导致Derived::data未释放
声明基类析构函数为虚函数后,delete
基类指针时会先调用派生类析构函数,再调用基类析构函数,保证资源被完整释放。
默认构造函数是指无需参数即可调用的构造函数。包括:
Data() {}
或 Data() = default
。// 若类中定义了任何构造函数(无论是否带参数),编译器不会自动生成默认构造函数。因此,以下两种情况都会导致默认构造函数缺失
struct Data1 {
Data1(int x) {} // 带参构造函数 → 无默认构造函数
};
struct Data2 {
Data2() {} // 用户显式定义无参构造函数 → 编译器不再生成默认构造函数
};
默认构造函数是编译器自动生成或用户显式定义的无参数构造函数,或者所有参数均有默认值的构造函数(如
MyClass(int x = 0)
)。其核心特点是无需传递参数即可调用。class MyClass { public: MyClass(int x = 0, double y = 1.0) { /* 参数均有默认值 */ } }; // 此时,MyClass obj; 或 MyClass obj{}; 均可调用该构造函数
无参构造函数(Parameterless Constructor)
无参构造函数是参数列表为空的构造函数,属于默认构造函数的一种特例。
MyClass() {}
)= default
)默认构造函数是一个更宽泛的概念,包括编译器生成的和用户定义的无参构造函数。
默认构造函数的显式声明方式
方式 1:用户自定义无参构造函数
class MyClass {
public:
MyClass() { // 自定义默认构造函数
// 初始化逻辑
}
};
方式 2:使用= default
强制编译器生成
class MyClass {
public:
MyClass() = default; // 显式要求编译器生成默认构造函数
};
当类定义了任何构造函数(包括无参构造函数)时,编译器不会自动生成默认构造函数。
可通过= default
显式请求。
class Data {
public:
Data(int val) : value(val) {} // 定义带参构造函数
Data() = default; // 显式生成默认构造函数
private:
int value;
};
派生类的构造函数会隐式调用基类的默认构造函数。若基类无默认构造函数,派生类必须显式调用基类的其他构造函数。
class Base {
public:
Base(int x) {} // 基类无默认构造函数
};
class Derived : public Base {
public:
Derived() : Base(0) {} // 必须显式调用Base的构造函数
};
聚合类(无用户声明构造函数、无私有 / 保护成员、无虚函数)可使用聚合初始化(花括号语法),即使没有默认构造函数。
struct Data {
int x;
Data(int x) : x(x) {} // 有带参构造函数,无默认构造函数
};
Data d{42}; // 合法:聚合初始化
Data d; // 非法:无默认构造函数
工程中的最佳实践:
const
和引用成员:必须通过构造函数初始化列表初始化,隐式默认构造函数无法处理class ConstDemo {
public:
const int c;
ConstDemo() : c(10) {} // 必须显式初始化
};
在C++中,每个类最多只能有一个默认构造函数,即以下两种形式不能同时存在:
若同时定义这两种形式,会导致编译错误
class Date {
public:
// 无参构造函数
Date() : _year(1), _month(1), _day(1) {} // 默认构造函数①
// 全缺省参数构造函数(等价于默认构造函数②)
Date(int year = 1, int month = 1, int day = 1)
: _year(year), _month(month), _day(day) {}
private:
int _year, _month, _day;
};
int main() {
Date d1; // 错误:存在多个默认构造函数
return 0;
}