15.5.1构造函数的定义与使用
数据成员多为私有的,要对它们进行初始化,必须用一个公有函数来进行。同时这个函数应该在且仅在定义对象时自动执行一次。称为构造函数。
构造函数用途:
1)创建对象
2)初始化对象中的属性
3)类型转换。
构造函数是特殊的公有成员函数(在特殊用途中构造函数的访问限定可以定义成私有或保护),其特征如下:
-
函数名与类名相同。
-
构造函数无函数返回类型说明。注意是没有而不是 void,即什么也不写,也不可写 void。实际上构造函数有返回值,返回的就是构造函数所创建的对象。
-
在程序运行时,当新的对象被建立,该对象所属的类构造函数自动被调用,在该对象生存期中也只调用这一次。
-
构造函数可以重载。严格地讲,类中可以定义多个构造函数,它们由不同的参数表区分,系统在自动调用时按一般函数重载的规则选一个执行。
-
构造函数可以在类中定义,也可以在类中声明,在类外定义。
-
如果类说明中没有给出构造函数,则 C++ 编译器自动给出一个缺省的构造函数:类名 (void) { }但只要我们定义了一个构造函数,系统就不会自动生成缺省的构造函数。只要构造函数是无参的或者只要各参数均有缺省值的,C++ 编译器都认为是缺省的构造函数,并且缺省的构造函数只能有一个。
示例 1:编译器自动生成缺省构造函数
#include <iostream>
using namespace std;
class MyClass {
private:
int num;
public:
// 类中未定义任何构造函数,编译器自动生成缺省构造函数:MyClass(void) {}
void show() {
cout << "num: " << num << endl; // 内置类型成员num会被初始化为随机值(不同编译器行为可能不同)
}
};
int main() {
MyClass obj; // 调用编译器自动生成的缺省构造函数
obj.show();
return 0;
}
示例 2:手动定义构造函数后,编译器不再生成缺省构造函数
#include <iostream>
using namespace std;
class MyClass {
private:
int num;
public:
// 手动定义了带参构造函数,编译器不再生成缺省构造函数
MyClass(int n) {
num = n;
}
void show() {
cout << "num: " << num << endl;
}
};
int main() {
// MyClass obj; // 错误!编译器未生成缺省构造函数,无参构造方式被禁用
MyClass obj(10); // 必须调用带参构造函数
obj.show();
return 0;
}
示例 3:定义无参的缺省构造函数
#include <iostream>
using namespace std;
class MyClass {
private:
int num;
public:
// 手动定义无参构造函数,作为缺省构造函数
MyClass() {
num = 0; // 显式初始化成员
}
void show() {
cout << "num: " << num << endl;
}
};
int main() {
MyClass obj; // 调用手动定义的无参缺省构造函数
obj.show(); // 输出:num: 0
return 0;
}
示例 4:定义带缺省参数的构造函数(视为缺省构造函数)
#include <iostream>
using namespace std;
class MyClass {
private:
int num;
public:
// 带缺省参数的构造函数,视为缺省构造函数
MyClass(int n = 0) {
num = n;
}
void show() {
cout << "num: " << num << endl;
}
};
int main() {
MyClass obj1; // 调用缺省构造函数,num = 0
MyClass obj2(5); // 调用带参构造函数,num = 5
obj1.show(); // 输出:num: 0
obj2.show(); // 输出:num: 5
return 0;
}
示例 5:缺省构造函数的唯一性(多个缺省构造会报错)
#include <iostream>
using namespace std;
class MyClass {
private:
int num;
public:
// 错误!定义了两个缺省构造函数(无参 + 全缺省参数),编译器会报“重定义”错误
MyClass() {
num = 0;
}
MyClass(int n = 0) {
num = n;
}
void show() {
cout << "num: " << num << endl;
}
};
int main() {
// MyClass obj; // 因构造函数重定义,编译失败
return 0;
}
15.5.2析构函数的定义与使用
当定义一个对象时,C++ 自动调用构造函数建立该对象并进行初始化,那么当一个对象的生命周期结束时,C++ 也会自动调用一个函数注销该对象并进行善后工作,这个特殊的成员函数即析构函数。
-
函数名与类名相同,但在前面加上字符
~,如:~CGoods()。 -
析构函数无函数返回类型,与构造函数在这方面是一样的。但析构函数不带任何参数。
-
一个类有一个也只有一个析构函数,这与构造函数不同。
-
对象注销时,系统自动调用析构函数。
-
如果类说明中没有给出析构函数,则 C++ 编译器自动给出一个缺省的析构函数。如:
~类型名称(){}
示例 1:基础析构函数使用
#include <iostream>
using namespace std;
class MyClass {
public:
// 构造函数:对象创建时调用
MyClass() {
cout << "构造函数调用,对象已创建" << endl;
}
// 析构函数:对象销毁时调用
~MyClass() {
cout << "析构函数调用,对象已销毁" << endl;
}
};
int main() {
{
MyClass obj; // 进入作用域,创建对象,调用构造函数
// 此处 obj 处于生命周期内
} // 离开作用域,对象销毁,自动调用析构函数
return 0;
}
示例 2:析构函数释放动态内存
#include <iostream>
using namespace std;
class MemoryDemo {
private:
int* ptr; // 指向动态分配的内存
public:
// 构造函数:申请堆内存
MemoryDemo() {
ptr = new int[10]; // 申请能存10个int的堆内存
cout << "构造函数:申请了堆内存" << endl;
}
// 析构函数:释放堆内存
~MemoryDemo() {
delete[] ptr; // 释放堆内存,避免内存泄漏
cout << "析构函数:释放了堆内存" << endl;
}
};
int main() {
MemoryDemo* obj = new MemoryDemo(); // 动态创建对象
delete obj; // 手动释放对象,触发析构函数
return 0;
}
示例 3:缺省析构函数的行为
#include <iostream>
using namespace std;
class DefaultDestructor {
private:
int num;
public:
DefaultDestructor() {
num = 10;
cout << "构造函数:num 初始化" << endl;
}
// 未定义析构函数,编译器自动生成缺省析构函数
};
int main() {
DefaultDestructor obj;
cout << "程序结束前,对象即将销毁" << endl;
return 0;
}
15.5.3总结
| 对比项 | 构造函数 | 析构函数 |
|---|---|---|
| 作用 | 创建对象,初始化成员 / 分配资源 | 销毁对象,清理资源 |
| 命名 | 与类名相同 | 与类名相同,前缀加 ~ |
| 参数 | 可带参数,支持重载 | 无参数,不可重载 |
| 调用时机 | 对象创建时 | 对象生命周期结束时 |
| 缺省实现 | 无参空函数(未定义时生成) | 空函数(未定义时生成) |
| 核心关注 | 初始化逻辑 | 资源释放逻辑 |
256

被折叠的 条评论
为什么被折叠?



