在 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. 成员方法的分类与访问权限

成员方法按访问权限可分为三类,通过访问限定符(publicprivateprotected)控制:

  1. 公有方法(public)

    • 对外提供的接口,用于类的使用者操作对象(如获取 / 修改属性、执行核心功能)。
    • 示例:getter/setter 方法、业务逻辑方法(如 calculate()display())。
  2. 私有方法(private)

    • 类内部的辅助方法,封装实现细节,不对外暴露(如数据校验、格式转换)。
    • 示例:validateData()formatString()
  3. 保护方法(protected)

    • 供子类继承和访问的方法,介于公有与私有之间,多用于继承场景。
2. 成员方法的设计原则
  1. 单一职责原则一个方法只负责完成一个具体功能,避免 “大而全” 的方法。

    • 反例:一个 processData() 既处理输入、又计算结果、还输出日志。
    • 正例:拆分为 readInput()calculateResult()logResult() 三个方法。
  2. 封装细节,暴露接口将复杂逻辑隐藏在私有方法中,仅通过公有方法对外提供简洁接口。

    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;
        }
    };
    
  3. 避免直接暴露成员变量优先通过 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;
        }
    };
    
  4. 使用 const 修饰只读方法对于不修改成员变量的方法,添加 const 关键字(放在参数列表后),提高代码安全性和可读性。

    class Book {
    private:
        string title;
    public:
        // const 方法:仅读取数据,不修改
        string getTitle() const {
            return title;
        }
        // 非 const 方法:可能修改数据
        void setTitle(string t) {
            title = t;
        }
    };
    
  5. 参数与返回值设计

    • 参数:优先使用引用(&)或 const 引用(const &)传递大对象,避免拷贝开销;基本类型直接传值。
    • 返回值:若返回内部数据,对于可修改的内容可返回引用,只读内容返回 const 引用或值。
3. 特殊成员方法的设计
  1. 构造函数与析构函数

    • 构造函数:负责初始化成员变量,可重载(如无参、带参、拷贝构造)。
    • 析构函数:负责释放资源(如动态内存、文件句柄),无参数、不可重载。
  2. 运算符重载根据类的语义重载运算符(如 +==<<),使对象操作更直观。

    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);
        }
    };
    
  3. 拷贝控制方法若类包含动态资源(如 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;
    }
};

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐