C24 对象生存期
1. 局部对象2. 全局对象3. 动态创建的对象1. 对于局部定义的对象,每当程序控制流到达该对象定义处时,调用构造函数。当程序控制走出该局部域时,则调用析构函数。2 对于静态局部定义的对象,在程序控制首次到达该对象定义处时,调用构造函数。当整个程序结束时调用析构函数。2. 对全局定义的对象,当程序进入入口函数 main 之前对象就已经定义,这时要调用构造函数。整个程序结束时调用析构函数。3. 动
在 C++ 中,对象的生存期(即对象从创建到销毁的时间段)根据其定义方式可分为以下三类:
1. 局部对象
2. 全局对象
3. 动态创建的对象
1. 对于局部定义的对象,每当程序控制流到达该对象定义处时,调用构造函数。当程序控制走出该局部域时,则调用析构函数。
2 对于静态局部定义的对象,在程序控制首次到达该对象定义处时,调用构造函数。当整个程序结束时调用析构函数。
2. 对全局定义的对象,当程序进入入口函数 main 之前对象就已经定义,这时要调用构造函数。整个程序结束时调用析构函数。
3. 动态创建的对象,使用 new 创建对象,delete 释放对象.
15.6.1局部对象
局部对象定义在函数内部或 代码块 中,其生存期与所在的局部作用域绑定:
- 构造时机:程序控制流执行到对象定义处时,自动调用构造函数创建对象。
- 析构时机:程序控制流离开该局部作用域时,自动调用析构函数销毁对象。
示例:
void func() {
{
MyClass obj; // 局部对象,进入代码块时构造
} // 离开代码块时析构
}
15.6.2 全局对象
全局对象定义在函数外部(通常在 .cpp 文件的全局作用域或头文件的全局声明中),其生存期贯穿整个程序:
- 构造时机:程序进入
main函数之前,自动调用构造函数创建对象。 - 析构时机:整个程序执行结束时(
main函数返回后),自动调用析构函数销毁对象。
示例:
MyClass globalObj; // 全局对象,main函数执行前构造,程序结束时析构
int main() {
// 程序逻辑
return 0;
}
15.6.3 动态创建的对象
动态创建的对象通过 new 操作在堆内存中分配,其生存期由程序员手动控制:
- 构造时机:执行
new操作时,显式调用构造函数创建对象。 - 析构时机:执行
delete操作时,显式调用析构函数销毁对象;若未手动delete,会导致内存泄漏。
示例:
int main() {
MyClass* p = new MyClass(); // 动态创建对象,手动构造
delete p; // 手动析构,释放堆内存
return 0;
}
补充:静态局部对象
静态局部对象是局部对象的特殊形式(通过 static 关键字定义),其生存期也具有特殊性:
- 构造时机:程序控制流首次执行到对象定义处时,调用构造函数创建对象(仅执行一次)。
- 析构时机:整个程序执行结束时,调用析构函数销毁对象。
示例:
void func() {
static MyClass staticObj; // 静态局部对象,首次进入函数时构造,程序结束时析构
}
15.6.4成员方法的设计
在 C++ 类的设计中,成员方法(成员函数)是实现类功能的核心,用于操作类的成员变量、对外提供接口或封装内部逻辑。成员方法的设计需遵循封装性、可读性、可维护性原则,同时明确方法的职责与访问权限。
1. 成员方法的分类与访问权限
成员方法按访问权限可分为三类,通过访问限定符(public、private、protected)控制:
-
公有方法(public)
- 对外提供的接口,用于类的使用者操作对象(如获取 / 修改属性、执行核心功能)。
- 示例:
getter/setter方法、业务逻辑方法(如calculate()、display())。
-
私有方法(private)
- 类内部的辅助方法,封装实现细节,不对外暴露(如数据校验、格式转换)。
- 示例:
validateData()、formatString()。
-
保护方法(protected)
- 供子类继承和访问的方法,介于公有与私有之间,多用于继承场景。
2. 成员方法的设计原则
-
单一职责原则一个方法只负责完成一个具体功能,避免 “大而全” 的方法。
- 反例:一个
processData()既处理输入、又计算结果、还输出日志。 - 正例:拆分为
readInput()、calculateResult()、logResult()三个方法。
- 反例:一个
-
封装细节,暴露接口将复杂逻辑隐藏在私有方法中,仅通过公有方法对外提供简洁接口。
class Calculator { private: // 私有辅助方法:校验输入合法性(内部细节) bool isValid(int a, int b) { return b != 0; // 假设用于除法校验 } public: // 公有接口:对外提供除法功能 double divide(int a, int b) { if (!isValid(a, b)) { throw "除数不能为0"; } return (double)a / b; } }; -
避免直接暴露成员变量优先通过
getter(获取值)和setter(设置值)方法操作成员变量,便于添加校验或日志。class Student { private: int age; // 私有成员,不直接暴露 public: // getter:获取年龄 int getAge() const { // const 修饰:确保不修改成员变量 return age; } // setter:设置年龄(带校验) void setAge(int a) { if (a < 0 || a > 150) { throw "年龄不合法"; } age = a; } }; -
使用 const 修饰只读方法对于不修改成员变量的方法,添加
const关键字(放在参数列表后),提高代码安全性和可读性。class Book { private: string title; public: // const 方法:仅读取数据,不修改 string getTitle() const { return title; } // 非 const 方法:可能修改数据 void setTitle(string t) { title = t; } }; -
参数与返回值设计
- 参数:优先使用引用(
&)或 const 引用(const &)传递大对象,避免拷贝开销;基本类型直接传值。 - 返回值:若返回内部数据,对于可修改的内容可返回引用,只读内容返回 const 引用或值。
- 参数:优先使用引用(
3. 特殊成员方法的设计
-
构造函数与析构函数
- 构造函数:负责初始化成员变量,可重载(如无参、带参、拷贝构造)。
- 析构函数:负责释放资源(如动态内存、文件句柄),无参数、不可重载。
-
运算符重载根据类的语义重载运算符(如
+、==、<<),使对象操作更直观。class Point { private: int x, y; public: Point(int x_, int y_) : x(x_), y(y_) {} // 重载 + 运算符:点的相加 Point operator+(const Point& other) const { return Point(x + other.x, y + other.y); } }; -
拷贝控制方法若类包含动态资源(如
new分配的内存),需手动设计拷贝构造函数和赋值运算符,避免浅拷贝问题。
4. 示例:一个完整的类成员方法设计
#include <string>
#include <stdexcept>
using namespace std;
class User {
private:
string name; // 用户名
int age; // 年龄
// 私有辅助方法:校验用户名合法性
bool isNameValid(const string& n) const {
return !n.empty() && n.length() <= 20;
}
public:
// 构造函数:初始化对象
User(string n, int a) {
if (!isNameValid(n)) {
throw invalid_argument("用户名必须非空且长度≤20");
}
name = n;
setAge(a); // 复用 setter 的校验逻辑
}
// getter:获取用户名(const 方法)
string getName() const {
return name;
}
// getter:获取年龄(const 方法)
int getAge() const {
return age;
}
// setter:设置年龄(带校验)
void setAge(int a) {
if (a < 0 || a > 150) {
throw invalid_argument("年龄必须在0-150之间");
}
age = a;
}
// 公有方法:显示用户信息
void display() const {
cout << "姓名:" << name << ",年龄:" << age << endl;
}
};
更多推荐


所有评论(0)