《类和对象》—— 构造函数与析构函数总结

在 C++ 面向对象编程中,类(Class)和对象(Object)是核心内容,而构造函数与析构函数则是类中最重要的两个特殊成员函数。它们负责对象的"出生"和"销毁",直接影响程序的资源管理和对象生命周期。

本文将系统整理本节课中关于构造函数与析构函数的核心知识点,并结合代码案例进行分析。


一、构造函数(Constructor)

1. 什么是构造函数

构造函数是一种特殊的成员函数,用于在对象创建时完成初始化工作。

特点:

  • 函数名与类名相同

  • 没有返回值

  • 对象创建时自动调用

  • 可以重载

基本语法

复制代码
class 类名
{
public:
    类名()
    {
        // 初始化代码
    }
};

2. 为什么需要构造函数

对象创建后,如果成员变量没有初始化,就会出现随机值。

例如:

复制代码
class Date
{
public:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d;
    cout << d._year << endl;
}

此时输出的是随机值。

因此,需要构造函数对对象进行初始化。


二、构造函数的分类


1. 无参构造函数(默认构造)

复制代码
class Date
{
public:
    Date()
    {
        _year = 2025;
        _month = 5;
        _day = 11;
    }

private:
    int _year;
    int _month;
    int _day;
};

调用方式

复制代码
Date d1;

注意:

复制代码
Date d1();

这不是创建对象,而是函数声明。


2. 带参构造函数

可以在创建对象时直接传入数据。

复制代码
class Date
{
public:
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }

private:
    int _year;
    int _month;
    int _day;
};

调用方式

复制代码
Date d1(2025, 5, 11);

3. 缺省参数构造函数

复制代码
class Date
{
public:
    Date(int year = 2025, int month = 1, int day = 1)
    {
        _year = year;
        _month = month;
        _day = day;
    }

private:
    int _year;
    int _month;
    int _day;
};

调用方式

复制代码
Date d1;
Date d2(2024, 10, 1);

三、构造函数的特性


1. 构造函数可以重载

复制代码
class Test
{
public:
    Test()
    {
        cout << "无参构造" << endl;
    }

    Test(int x)
    {
        cout << "带参构造" << endl;
    }
};

调用

复制代码
Test t1;
Test t2(10);

2. 对象创建时自动调用

复制代码
Date d1;

对象一创建:

  • 自动调用构造函数

  • 不需要手动调用


3. 如果没有写构造函数

编译器会自动生成默认构造函数。

复制代码
class A
{
private:
    int x;
};

系统会自动生成:

复制代码
A()
{
}

但是:

  • 内置类型不会初始化

  • 自定义类型会调用其默认构造


四、初始化列表


1. 什么是初始化列表

初始化列表是构造函数初始化成员变量的一种方式。

语法

复制代码
class Date
{
public:
    Date(int year, int month, int day)
        : _year(year)
        , _month(month)
        , _day(day)
    {
    }

private:
    int _year;
    int _month;
    int _day;
};

2. 为什么推荐使用初始化列表

因为:

  • 效率更高

  • 某些成员必须使用初始化列表

例如:

const成员

复制代码
const int _a;

引用成员

复制代码
int& _ref;

没有默认构造的对象成员

复制代码
class A
{
public:
    A(int a)
    {}
};

class B
{
public:
    B(int b)
        : _aa(b)
    {}

private:
    A _aa;
};

五、析构函数(Destructor)


1. 什么是析构函数

析构函数用于对象销毁时释放资源。

特点:

  • 函数名前加 ~

  • 无参数

  • 无返回值

  • 一个类只能有一个析构函数

  • 对象生命周期结束时自动调用


2. 基本语法

复制代码
class Test
{
public:
    ~Test()
    {
        cout << "析构函数调用" << endl;
    }
};

3. 析构函数的作用

主要用于:

  • 释放动态内存

  • 关闭文件

  • 释放系统资源

例如:

复制代码
class Stack
{
public:
    Stack(int n = 10)
    {
        _a = (int*)malloc(sizeof(int) * n);
        _capacity = n;
        _top = 0;
    }

    ~Stack()
    {
        free(_a);
        _a = nullptr;
        _capacity = 0;
        _top = 0;
    }

private:
    int* _a;
    int _top;
    int _capacity;
};

六、构造函数与析构函数的调用顺序


1. 单个对象

复制代码
Test t;

执行顺序:

复制代码
构造函数
析构函数

2. 多个对象

复制代码
Test t1;
Test t2;

执行顺序:

复制代码
构造 t1
构造 t2
析构 t2
析构 t1

规律:

  • 先构造的后析构

  • 类似栈结构(先进后出)


七、隐式生成的成员函数

C++ 编译器默认会生成:

  • 默认构造函数

  • 析构函数

  • 拷贝构造

  • 赋值运算符重载

其中:

默认析构函数

如果类中没有动态资源:

系统默认析构即可。

如果类中有动态申请资源:

必须自己写析构函数。


八、经典问题分析


1. 为什么析构函数不能重载?

因为对象销毁时:

编译器无法判断调用哪一个析构函数。

所以:

  • 一个类只能有一个析构函数

2. 构造函数能否是 void

不能。

构造函数没有返回值。

写成:

复制代码
void Test()

这已经是普通成员函数。


3. 构造函数可以被手动调用吗?

理论上可以:

复制代码
t.Test();

但不推荐。

因为对象初始化只应该进行一次。


九、总结

构造函数与析构函数是 C++ 类和对象中最核心的内容之一。

构造函数

负责:

  • 对象初始化

  • 建立对象状态

重点掌握:

  • 默认构造

  • 带参构造

  • 初始化列表

  • 构造函数重载


析构函数

负责:

  • 对象销毁

  • 资源释放

重点掌握:

  • 自动调用机制

  • 动态资源释放

  • 生命周期管理


十、学习建议

学习构造与析构时,建议重点理解:

  1. 对象生命周期

  2. 自动调用机制

  3. 初始化列表本质

  4. 动态内存管理

  5. RAII思想

因为后续:

  • 拷贝构造

  • 运算符重载

  • STL

  • 智能指针

都会建立在这些基础之上。


结语

构造函数和析构函数看似只是两个特殊函数,但它们本质上体现了 C++ 对"资源管理"和"对象生命周期"的核心思想。

真正理解它们之后,才能深入掌握 C++ 面向对象编程。

相关推荐
Patrick_Wilson32 分钟前
修好 bug 只是开始:一次由监控需求反向重构日志结构的复盘
前端·监控·数据可视化
kyriewen1 小时前
面试官让我优化一个卡死的表格,我打开 Claude 五秒重写,他放下咖啡问我要不要来当组长
前端·javascript·面试
小粉粉hhh1 小时前
React(二)——dom、组件间通信、useEffect
前端·javascript·react.js
Csvn2 小时前
🤖 AI 生成前端代码的 5 个典型翻车现场及修复指南
前端
charlie1145141912 小时前
Cinux: 为大内核铺路
开发语言·c++·操作系统·现代c++
IT_陈寒3 小时前
SpringBoot自动装配坑了我一天,原来问题出在这
前端·人工智能·后端
Jerry3 小时前
LeetCode 101. 对称二叉树
算法
索西引擎3 小时前
【React】key 属性:协调算法中的元素标识机制与最佳实践
前端·javascript·react.js
只会cv的前端攻城狮4 小时前
动态组件架构设计:从配置到事件驱动全链路解析
前端·vue.js
飞天狗4 小时前
Next.js 16 App Router 实战:服务端组件与流式渲染
前端·next.js