C++ 构造函数和析构函数示例详解

 更新时间:2025年11月13日 09:36:42   作者:赫尔·普莱蒂科萨·帕塔  
本文详细介绍了C++中的构造函数和析构函数,包括它们的特点、调用时机以及在资源管理中的重要性,同时,通过与Python的对比,展示了如何在Python中模拟C++的构造函数特性,并强调了两种语言在内存管理和资源管理机制上的差异,感兴趣的朋友跟随小编一起看看吧

构造函数(Constructor)

什么是构造函数?

构造函数是一种特殊的成员函数,在创建类对象时自动调用,用于初始化对象的数据成员。

构造函数的特点

  1. 与类同名
  2. 没有返回类型
  3. 可以重载
  4. 自动调用

构造函数的类型

1. 默认构造函数

class MyClass {
private:
    int value;
    std::string name;
public:
    // 默认构造函数(无参数)
    MyClass() {
        value = 0;
        name = "Unknown";
        std::cout << "Default constructor called" << std::endl;
    }
};
// 使用
MyClass obj;  // 调用默认构造函数

2. 参数化构造函数

class MyClass {
private:
    int value;
    std::string name;
public:
    // 参数化构造函数
    MyClass(int val, const std::string& n) {
        value = val;
        name = n;
        std::cout << "Parameterized constructor called" << std::endl;
    }
};
// 使用
MyClass obj1(42, "Hello");
MyClass obj2 = MyClass(100, "World");

3. 拷贝构造函数

class MyClass {
private:
    int value;
    std::string name;
public:
    // 拷贝构造函数
    MyClass(const MyClass& other) {
        value = other.value;
        name = other.name;
        std::cout << "Copy constructor called" << std::endl;
    }
};
// 使用
MyClass obj1(42, "Original");
MyClass obj2 = obj1;  // 调用拷贝构造函数
MyClass obj3(obj1);   // 调用拷贝构造函数

4. 移动构造函数(C++11)

class MyClass {
private:
    int* data;
    size_t size;
public:
    // 移动构造函数
    MyClass(MyClass&& other) noexcept {
        // "窃取"资源
        data = other.data;
        size = other.size;
        // 置空原对象
        other.data = nullptr;
        other.size = 0;
        std::cout << "Move constructor called" << std::endl;
    }
};

初始化列表

class Student {
private:
    std::string name;
    int age;
    const int id;  // 常量成员
    int& ref;      // 引用成员
public:
    // 使用初始化列表(推荐)
    Student(const std::string& n, int a, int studentId, int& r) 
        : name(n), age(a), id(studentId), ref(r) {
        std::cout << "Student constructor called" << std::endl;
    }
    // 错误示例:不能在构造函数体内初始化常量和引用
    // Student(const std::string& n, int a, int studentId, int& r) {
    //     name = n;
    //     age = a;
    //     id = studentId;  // 错误!常量必须在初始化列表中初始化
    //     ref = r;         // 错误!引用必须在初始化列表中初始化
    // }
};

析构函数(Destructor)

什么是析构函数?

析构函数是一种特殊的成员函数,在对象销毁时自动调用,用于清理资源。

析构函数的特点

  1. 类名前加 ~
  2. 没有参数
  3. 没有返回类型
  4. 不能重载
  5. 自动调用

析构函数示例

class MyClass {
private:
    int* data;
    size_t size;
public:
    // 构造函数
    MyClass(size_t s) : size(s) {
        data = new int[size];  // 动态分配内存
        std::cout << "Constructor: allocated " << size << " integers" << std::endl;
    }
    // 析构函数
    ~MyClass() {
        delete[] data;  // 释放内存
        std::cout << "Destructor: freed " << size << " integers" << std::endl;
    }
};
// 使用
void test() {
    MyClass obj(100);  // 构造函数调用
    // ... 使用 obj
}  // obj 离开作用域,析构函数自动调用

完整示例

资源管理类示例

#include <iostream>
#include <cstring>
class String {
private:
    char* data;
    size_t length;
public:
    // 默认构造函数
    String() : data(nullptr), length(0) {
        std::cout << "Default constructor" << std::endl;
    }
    // 参数化构造函数
    String(const char* str) {
        length = std::strlen(str);
        data = new char[length + 1];
        std::strcpy(data, str);
        std::cout << "Parameterized constructor: " << data << std::endl;
    }
    // 拷贝构造函数
    String(const String& other) {
        length = other.length;
        data = new char[length + 1];
        std::strcpy(data, other.data);
        std::cout << "Copy constructor: " << data << std::endl;
    }
    // 移动构造函数(C++11)
    String(String&& other) noexcept {
        // 窃取资源
        data = other.data;
        length = other.length;
        // 置空原对象
        other.data = nullptr;
        other.length = 0;
        std::cout << "Move constructor" << std::endl;
    }
    // 拷贝赋值运算符
    String& operator=(const String& other) {
        if (this != &other) {  // 防止自赋值
            delete[] data;  // 释放原有资源
            length = other.length;
            data = new char[length + 1];
            std::strcpy(data, other.data);
        }
        std::cout << "Copy assignment: " << data << std::endl;
        return *this;
    }
    // 移动赋值运算符(C++11)
    String& operator=(String&& other) noexcept {
        if (this != &other) {
            delete[] data;  // 释放原有资源
            // 窃取资源
            data = other.data;
            length = other.length;
            // 置空原对象
            other.data = nullptr;
            other.length = 0;
        }
        std::cout << "Move assignment" << std::endl;
        return *this;
    }
    // 析构函数
    ~String() {
        delete[] data;
        std::cout << "Destructor" << std::endl;
    }
    // 其他成员函数
    const char* c_str() const { return data ? data : ""; }
    size_t size() const { return length; }
};
// 使用示例
int main() {
    std::cout << "=== 创建对象 ===" << std::endl;
    String s1;                    // 默认构造函数
    String s2 = "Hello";          // 参数化构造函数
    String s3 = s2;               // 拷贝构造函数
    std::cout << "\n=== 赋值操作 ===" << std::endl;
    s1 = s3;                      // 拷贝赋值
    s1 = String("World");         // 移动赋值
    std::cout << "\n=== 函数调用 ===" << std::endl;
    {
        String temp = "Temporary"; // 参数化构造函数
    } // temp 离开作用域,调用析构函数
    std::cout << "\n=== 程序结束 ===" << std::endl;
    return 0;
} // s1, s2, s3 离开作用域,调用析构函数

输出结果

=== 创建对象 ===
Default constructor
Parameterized constructor: Hello
Copy constructor: Hello
=== 赋值操作 ===
Copy assignment: Hello
Parameterized constructor: World
Move assignment
Destructor
=== 函数调用 ===
Parameterized constructor: Temporary
Destructor
=== 程序结束 ===
Destructor
Destructor
Destructor

特殊成员函数规则

Rule of Three/Five/Zero

Rule of Three(C++98/03)

如果一个类需要以下之一,通常需要全部三个:

  • 析构函数
  • 拷贝构造函数
  • 拷贝赋值运算符

Rule of Five(C++11及以后)

如果类管理资源,应该考虑定义全部五个特殊成员函数:

  • 析构函数
  • 拷贝构造函数
  • 拷贝赋值运算符
  • 移动构造函数
  • 移动赋值运算符

Rule of Zero

理想情况下,类不应该自己管理资源,而是使用智能指针等RAII类,这样编译器生成的默认函数就足够了。

// Rule of Zero 示例
class GoodClass {
private:
    std::unique_ptr<int[]> data;  // 使用智能指针管理资源
    std::string name;             // 使用标准库类
public:
    // 不需要定义析构函数、拷贝/移动构造函数、拷贝/移动赋值运算符
    // 编译器生成的默认函数就足够好
    GoodClass(const std::string& n) : name(n) {}
};

虚析构函数

class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    virtual ~Base() { std::cout << "Base destructor" << std::endl; }  // 虚析构函数
};
class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor" << std::endl; }
    ~Derived() override { std::cout << "Derived destructor" << std::endl; }
};
// 使用
Base* ptr = new Derived();
delete ptr;  // 正确调用 Derived 的析构函数,因为有虚析构函数

总结

  • 构造函数:对象创建时调用,用于初始化
  • 析构函数:对象销毁时调用,用于清理资源
  • 重要规则
    • 使用初始化列表初始化成员
    • 管理资源的类需要遵循 Rule of Five
    • 基类应该使用虚析构函数
    • 优先使用 Rule of Zero

构造函数和析构函数是C++中实现RAII(资源获取即初始化)模式的基础,对于资源管理和异常安全至关重要。

c++中的构造函数,如果类比python语言的话,在python中相当于什么?

C++ 构造函数与 Python 的类比

基本对应关系

C++ 概念Python 对应说明
构造函数__init__ 方法对象初始化
析构函数__del__ 方法对象清理
默认构造函数无参数的 __init__创建默认对象
拷贝构造函数__init__ + 手动拷贝对象拷贝
移动构造函数无直接对应Python 使用引用计数

详细对比

1. 基本构造函数 ↔__init__方法

C++:

class Person {
private:
    std::string name;
    int age;
public:
    // 构造函数
    Person(const std::string& n, int a) : name(n), age(a) {
        std::cout << "Person created: " << name << std::endl;
    }
};
// 使用
Person p("Alice", 25);

Python:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print(f"Person created: {self.name}")
# 使用
p = Person("Alice", 25)

2. 默认构造函数 ↔ 无参数__init__

C++:

class MyClass {
public:
    MyClass() {
        std::cout << "Default constructor" << std::endl;
    }
};
MyClass obj;  // 调用默认构造函数

Python:

class MyClass:
    def __init__(self):
        print("Default constructor")
obj = MyClass()  # 调用 __init__

3. 析构函数 ↔__del__方法

C++:

class FileHandler {
private:
    FILE* file;
public:
    FileHandler(const char* filename) {
        file = fopen(filename, "r");
        std::cout << "File opened" << std::endl;
    }
    ~FileHandler() {
        if (file) {
            fclose(file);
            std::cout << "File closed" << std::endl;
        }
    }
};
// 自动调用析构函数
{
    FileHandler fh("test.txt");
    // 使用文件
} // 离开作用域,自动调用析构函数

Python:

class FileHandler:
    def __init__(self, filename):
        self.file = open(filename, 'r')
        print("File opened")
    def __del__(self):
        if self.file:
            self.file.close()
            print("File closed")
# 使用(注意:Python的__del__调用时机不确定)
fh = FileHandler("test.txt")
# 当对象被垃圾回收时调用 __del__

4. 拷贝行为对比

C++ 拷贝构造函数:

class Vector {
private:
    int* data;
    size_t size;
public:
    Vector(size_t s) : size(s) {
        data = new int[size];
    }
    // 拷贝构造函数
    Vector(const Vector& other) : size(other.size) {
        data = new int[size];
        std::copy(other.data, other.data + size, data);
        std::cout << "Copy constructor called" << std::endl;
    }
    ~Vector() {
        delete[] data;
    }
};
Vector v1(10);
Vector v2 = v1;  // 调用拷贝构造函数

Python 的拷贝行为:

class Vector:
    def __init__(self, size):
        self.size = size
        self.data = [0] * size
    # Python 没有直接的拷贝构造函数
    # 需要手动实现或使用 copy 模块
v1 = Vector(10)
v2 = v1  # 这只是引用赋值,两个变量指向同一个对象
v3 = Vector(v1.size)  # 手动创建新对象
v3.data = v1.data[:]  # 手动拷贝数据
# 或者使用 copy 模块
import copy
v4 = copy.deepcopy(v1)

重要差异

1. 内存管理方式不同

C++ - 手动管理,确定性析构:

{
    Person p("John", 30);  // 构造函数调用
    // 使用 p
} // p 离开作用域,析构函数立即调用

Python - 自动垃圾回收,非确定性析构:

def test():
    p = Person("John", 30)  # __init__ 调用
    # 使用 p
    # __del__ 可能在函数结束后调用,也可能不立即调用

2. 拷贝语义不同

C++ - 值语义,默认深拷贝:

Vector v1(10);
Vector v2 = v1;  // 深拷贝,两个独立对象

Python - 引用语义,默认浅拷贝:

v1 = Vector(10)
v2 = v1  # 引用拷贝,两个变量指向同一个对象

3. 构造方式不同

C++ - 多种构造方式:

Person p1;              // 默认构造
Person p2("Alice", 25); // 直接构造
Person p3 = p2;         // 拷贝构造
Person p4 = Person("Bob", 30);  // 临时对象 + 移动构造

Python - 统一使用 __init__

p1 = Person()           # 需要定义 __init__(self)
p2 = Person("Alice", 25)
p3 = p2                 # 引用赋值,不是拷贝
p4 = Person(p2.name, p2.age)  # 手动创建新对象

Python 中模拟 C++ 构造函数特性

模拟重载构造函数

Python 使用默认参数和类方法模拟:

class Date:
    def __init__(self, day=1, month=1, year=2000):
        self.day = day
        self.month = month
        self.year = year
    @classmethod
    def from_string(cls, date_str):
        """模拟重载构造函数 - 从字符串创建"""
        day, month, year = map(int, date_str.split('/'))
        return cls(day, month, year)
    @classmethod
    def from_timestamp(cls, timestamp):
        """模拟重载构造函数 - 从时间戳创建"""
        # 实现时间戳转换逻辑
        return cls(1, 1, 2000)  # 简化示例
# 使用不同的"构造函数"
d1 = Date()                    # 默认构造
d2 = Date(15, 12, 2023)       # 参数化构造
d3 = Date.from_string("25/12/2023")  # 工厂方法
d4 = Date.from_timestamp(1700000000)

模拟 RAII (资源获取即初始化)

Python 使用上下文管理器模拟:

# C++ RAII 风格
class FileHandler:
    def __init__(self, filename, mode='r'):
        self.file = open(filename, mode)
        print(f"File {filename} opened")
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.file.close()
        print("File closed")
    def read(self):
        return self.file.read()
# 使用(类似C++的确定性析构)
with FileHandler("test.txt") as fh:
    content = fh.read()
    # 离开 with 块自动关闭文件

实际示例对比

完整的类设计对比

C++:

class BankAccount {
private:
    std::string owner;
    double balance;
    static int accountCount;  // 静态成员
public:
    // 构造函数
    BankAccount(const std::string& name, double initialBalance = 0.0) 
        : owner(name), balance(initialBalance) {
        accountCount++;
        std::cout << "Account created for " << owner << std::endl;
    }
    // 拷贝构造函数
    BankAccount(const BankAccount& other) 
        : owner(other.owner + " (copy)"), balance(other.balance) {
        accountCount++;
        std::cout << "Account copied" << std::endl;
    }
    // 析构函数
    ~BankAccount() {
        accountCount--;
        std::cout << "Account for " << owner << " destroyed" << std::endl;
    }
    // 成员函数
    void deposit(double amount) {
        balance += amount;
    }
    static int getAccountCount() {
        return accountCount;
    }
};
int BankAccount::accountCount = 0;

Python:

class BankAccount:
    _account_count = 0  # 类变量(类似静态成员)
    def __init__(self, name, initial_balance=0.0):
        self.owner = name
        self.balance = initial_balance
        BankAccount._account_count += 1
        print(f"Account created for {self.owner}")
    def __del__(self):
        BankAccount._account_count -= 1
        print(f"Account for {self.owner} destroyed")
    def deposit(self, amount):
        self.balance += amount
    @classmethod
    def get_account_count(cls):
        return cls._account_count
    # Python 没有内置的拷贝构造,但可以添加一个方法
    @classmethod
    def from_existing(cls, existing_account, new_name):
        """模拟拷贝构造"""
        new_account = cls(new_name, existing_account.balance)
        return new_account

总结

  • __init__ ≈ 构造函数:都用于对象初始化
  • __del__ ≈ 析构函数:都用于清理,但调用时机不同
  • 主要差异
    • C++ 有确定的构造/析构时机,Python 依赖垃圾回收
    • C++ 默认值语义,Python 默认引用语义
    • C++ 支持构造函数重载,Python 使用默认参数和类方法模拟
    • C++ 有专门的拷贝/移动构造函数,Python 需要手动处理

理解这些差异有助于在两种语言间转换思维,但要注意它们的设计哲学和内存管理机制有很大不同。

到此这篇关于C++ 构造函数和析构函数示例详解的文章就介绍到这了,更多相关C++ 构造函数和析构函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解如何将Spire.Doc for C++集成到C++程序中

    详解如何将Spire.Doc for C++集成到C++程序中

    Spire.Doc for C++是一个专业的Word库,供开发人员在任何类型的C++应用程序中阅读、创建、编辑、比较和转换 Word 文档,本文演示了如何以两种不同的方式将 Spire.Doc for C++ 集成到您的 C++ 应用程序中,希望对大家有所帮助
    2023-05-05
  • C++获取系统时间的三种方法

    C++获取系统时间的三种方法

    在 C++ 编程中,获取系统时间是一项常见任务,无论是记录日志、计算程序运行时间,还是实现计时功能,都需要获取当前的系统时间,本文将介绍几种在 C++ 中获取系统时间的方法,并提供相应的代码示例,需要的朋友可以参考下
    2024-09-09
  • c语言使用fdk_aac实现aac音频解码为pcm

    c语言使用fdk_aac实现aac音频解码为pcm

    这篇文章主要为大家详细介绍了c语言如何使用fdk_aac库实现aac音频解码为pcm的功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-11-11
  • 一文详解C++11中auto的使用

    一文详解C++11中auto的使用

    这篇文章主要为大家分享一下C++11中auto关键字的使用示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2023-07-07
  • C++实现简单FTP客户端软件开发

    C++实现简单FTP客户端软件开发

    这篇文章主要为大家详细介绍了C++实现简单FTP客户端软件开发,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C++标准库实现WAV文件读写的操作

    C++标准库实现WAV文件读写的操作

    本文将使用标准C++库实现对数据为PCM格式的WAV文件的读写操作,只使用标准C++库函数,不依赖于其他的库,对C++标准库实现WAV文件读写相关知识感兴趣的朋友一起看看吧
    2022-01-01
  • C++的静态联编和动态联编

    C++的静态联编和动态联编

    本文阐述了静态联编和动态联编的概念和区别,通过具体实例分析了实现动态联编的条件,指出了虚函数是实现动态联编的基础。
    2016-03-03
  • 深入探究C/C++中互斥量(锁)的实现原理

    深入探究C/C++中互斥量(锁)的实现原理

    ​ 互斥量是一种同步原语,用于保护多个线程同时访问共享数据,互斥量提供独占的、非递归的所有权语义,本文将和大家一起深入探究C/C++中互斥量(锁)的实现原理,感兴趣的小伙伴跟着小编一起来看看吧
    2024-06-06
  • C/C++中字符串流详解及其作用介绍

    C/C++中字符串流详解及其作用介绍

    这篇文章主要介绍了C/C++中字符串流详解及其作用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • 解析C++中的虚拟函数及其静态类型和动态类型

    解析C++中的虚拟函数及其静态类型和动态类型

    虚拟函数(Visual Function)亦常被成为虚函数,是C++中的一个重要特性,本文我们就来解析C++中的虚拟函数及其静态类型和动态类型
    2016-06-06

最新评论