Skip to content

C++构造函数与析构函数

构造函数和析构函数是C++类中特殊的成员函数,用于对象的初始化和清理。

简单说,构造函数负责初始化类,析构函数负责销毁对象是的清理工作。

关键要点总结

构造函数特点:

  1. 与类同名,没有返回类型
  2. 可以重载,支持多个构造函数版本
  3. 自动调用,创建对象时自动执行
  4. 初始化列表:推荐使用,效率更高,可以初始化const成员和引用成员
  5. 特殊构造函数
    • 默认构造函数:无参数或所有参数有默认值
    • 拷贝构造函数:ClassName(const ClassName& other)
    • 移动构造函数(C++11):ClassName(ClassName&& other)
    • 委托构造函数(C++11):一个构造函数可以调用另一个

析构函数特点:

  1. 名称格式~ClassName()
  2. 没有参数,不能重载(每个类只有一个析构函数)
  3. 自动调用,对象销毁时自动执行
  4. 主要用途:释放动态分配的内存、关闭文件、释放网络连接等资源清理工作
  5. 调用时机
    • 局部对象:离开作用域时
    • 动态分配对象:使用delete
    • 全局/静态对象:程序结束时

重要原则:

  1. RAII原则:资源获取即初始化,通过构造函数获取资源,通过析构函数释放资源
  2. 三法则:如果需要自定义析构函数、拷贝构造函数或拷贝赋值运算符中的任何一个,通常需要同时定义这三个
  3. 五法则(C++11):增加了移动构造函数和移动赋值运算符的考虑
  4. 零法则:如果不需要管理资源,让编译器生成默认的特殊成员函数

掌握构造函数和析构函数是理解C++对象生命周期和资源管理的基础。

示例

构造函数在创建对象时自动调用,用于初始化对象的成员变量。

cpp
#include <iostream>
#include <string>
using namespace std;

// 1. 默认构造函数(无参数)
class Person {
private:
    string name;
    int age;
    
public:
    // 默认构造函数
    Person() {
        name = "未知";
        age = 0;
        cout << "默认构造函数被调用" << endl;
    }
    
    // 2. 带参数的构造函数
    Person(string n, int a) {
        name = n;
        age = a;
        cout << "带参数构造函数被调用" << endl;
    }
    
    void display() {
        cout << "姓名: " << name << ", 年龄: " << age << endl;
    }
};

// 3. 使用初始化列表的构造函数
class Student {
private:
    string name;
    int score;
    const int id;  // 常量成员,必须在初始化列表中初始化
    
public:
    // 初始化列表构造函数(效率更高)
    Student(string n, int s, int i) : name(n), score(s), id(i) {
        cout << "学生" << name << "被创建,ID: " << id << endl;
    }
    
    void show() {
        cout << "学生" << name << ",分数: " << score << ",ID: " << id << endl;
    }
};

int main() {
    // 调用默认构造函数
    Person p1;
    p1.display();
    
    // 调用带参数构造函数
    Person p2("张三", 25);
    p2.display();
    
    // 调用初始化列表构造函数
    Student s1("李四", 95, 1001);
    s1.show();
    
    return 0;
}
cpp
#include <iostream>
#include <string>
using namespace std;

class Book {
private:
    string title;
    string author;
    double price;
    int* sales;  // 动态分配的内存
    
public:
    // 1. 构造函数重载
    Book() : title("未命名"), author("未知"), price(0.0), sales(nullptr) {
        cout << "默认构造函数" << endl;
    }
    
    Book(string t) : title(t), author("未知"), price(0.0), sales(nullptr) {
        cout << "单参数构造函数" << endl;
    }
    
    Book(string t, string a, double p) : title(t), author(a), price(p) {
        sales = new int[12];  // 为12个月的销量分配内存
        for (int i = 0; i < 12; i++) sales[i] = 0;
        cout << "三参数构造函数" << endl;
    }
    
    // 2. 拷贝构造函数(深拷贝)
    Book(const Book& other) {
        title = other.title;
        author = other.author;
        price = other.price;
        
        // 深拷贝:为新对象分配独立的内存
        if (other.sales != nullptr) {
            sales = new int[12];
            for (int i = 0; i < 12; i++) {
                sales[i] = other.sales[i];
            }
        } else {
            sales = nullptr;
        }
        cout << "拷贝构造函数被调用" << endl;
    }
    
    // 3. 移动构造函数(C++11)
    Book(Book&& other) noexcept {
        title = move(other.title);
        author = move(other.author);
        price = other.price;
        sales = other.sales;  // 转移资源所有权
        
        other.sales = nullptr;  // 源对象置空
        other.price = 0.0;
        cout << "移动构造函数被调用" << endl;
    }
    
    // 4. 委托构造函数(C++11)
    Book(string t, string a) : Book(t, a, 0.0) {
        // 委托给三参数构造函数
        cout << "委托构造函数完成任务" << endl;
    }
    
    // 成员函数
    void display() {
        cout << "《" << title << "》作者:" << author 
             << ",价格:" << price << "元" << endl;
    }
    
    // 设置销量
    void setSales(int month, int count) {
        if (sales != nullptr && month >= 1 && month <= 12) {
            sales[month-1] = count;
        }
    }
    
    // 析构函数声明(将在下一个代码块详细讲解)
    ~Book();
};

// 测试函数
void testBook() {
    cout << "=== 创建book1 ===" << endl;
    Book book1("C++ Primer", "Stanley Lippman", 99.9);
    book1.setSales(1, 100);
    book1.display();
    
    cout << "\n=== 拷贝构造book2 ===" << endl;
    Book book2 = book1;  // 调用拷贝构造函数
    book2.display();
    
    cout << "\n=== 移动构造book3 ===" << endl;
    Book book3 = move(book1);  // 调用移动构造函数
    book3.display();
    
    cout << "\n=== 委托构造book4 ===" << endl;
    Book book4("Effective C++", "Scott Meyers");
    book4.display();
}

int main() {
    testBook();
    return 0;
}
cpp
#include <iostream>
#include <string>
using namespace std;

// 析构函数(Destructor)
// 在对象销毁时自动调用,用于清理资源
class Book {
private:
    string title;
    string author;
    double price;
    int* sales;  // 动态分配的内存
    
public:
    // 构造函数
    Book(string t, string a, double p) : title(t), author(a), price(p) {
        sales = new int[12];
        for (int i = 0; i < 12; i++) sales[i] = 0;
        cout << "构造函数: " << title << endl;
    }
    
    // 拷贝构造函数
    Book(const Book& other) {
        title = other.title + "(副本)";
        author = other.author;
        price = other.price;
        sales = new int[12];
        for (int i = 0; i < 12; i++) sales[i] = other.sales[i];
        cout << "拷贝构造: " << title << endl;
    }
    
    // 析构函数
    ~Book() {
        cout << "析构函数: " << title;
        // 释放动态分配的内存
        if (sales != nullptr) {
            delete[] sales;
            sales = nullptr;
            cout << " (内存已释放)" << endl;
        } else {
            cout << " (无动态内存)" << endl;
        }
    }
    
    void display() {
        cout << "《" << title << "》作者:" << author 
             << ",价格:" << price << "元" << endl;
    }
};

// 演示析构函数调用时机
class Resource {
private:
    string name;
    
public:
    Resource(string n) : name(n) {
        cout << "资源" << name << "被创建" << endl;
    }
    
    ~Resource() {
        cout << "资源" << name << "被销毁" << endl;
    }
};

class Container {
private:
    Resource* res;
    
public:
    Container(string name) {
        res = new Resource(name);
        cout << "容器被创建" << endl;
    }
    
    ~Container() {
        delete res;  // 释放资源
        cout << "容器被销毁" << endl;
    }
};

// 演示局部对象、全局对象、动态分配对象的生命周期
void testLifecycle() {
    cout << "\n=== 进入testLifecycle函数 ===" << endl;
    
    // 1. 局部对象 - 函数结束时自动销毁
    Book localBook("局部书", "局部作者", 50.0);
    
    // 2. 动态分配的对象 - 需要手动delete才会调用析构函数
    Book* dynamicBook = new Book("动态书", "动态作者", 60.0);
    
    cout << "\n=== 创建块作用域对象 ===" << endl;
    {
        // 3. 块作用域对象 - 离开块时自动销毁
        Book blockBook("块作用域书", "块作者", 70.0);
    }
    cout << "=== 离开块作用域 ===" << endl;
    
    // 必须手动删除动态分配的对象
    delete dynamicBook;
    dynamicBook = nullptr;
    
    cout << "=== 即将离开testLifecycle函数 ===" << endl;
    // localBook的析构函数将在这里自动调用
}

// 全局对象 - 程序结束时销毁
Book globalBook("全局书", "全局作者", 80.0);

// 静态局部对象 - 程序结束时销毁
void testStatic() {
    static Book staticBook("静态书", "静态作者", 90.0);
    cout << "静态对象测试函数" << endl;
}

int main() {
    cout << "=== 程序开始 ===" << endl;
    
    testLifecycle();
    
    cout << "\n=== 测试静态对象 ===" << endl;
    testStatic();
    testStatic();  // 第二次调用不会创建新对象
    
    cout << "\n=== 测试容器类 ===" << endl;
    Container container("我的资源");
    
    cout << "\n=== main函数即将结束 ===" << endl;
    // globalBook和staticBook的析构函数将在这里调用
    return 0;
}