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

在 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++ 面向对象编程。

相关推荐
程序员黑豆28 分钟前
鸿蒙应用开发:V1与V2版本数据持久化实战教程
前端·harmonyos
小月土星4 小时前
React Router 前端路由深度解析:从传统后端路由到现代 SPA 的完整演进
前端
程序员黑豆4 小时前
鸿蒙开发 Navigation 路由教程:从入门到实战
前端·harmonyos
用户938515635077 小时前
从零理解 React Router v6:每一个 API 都是怎么工作的
前端·javascript·全栈
小程故事多_807 小时前
从A2C、TRPO、PPO到GRPO,强化学习策略梯度算法完整演进与大模型落地实战解析
人工智能·算法
2601_956121978 小时前
二分算法(知识点+题目)
c++·算法
用户059540174469 小时前
Redis缓存回滚踩坑实录:一个配置失误,让我在凌晨3点丢了3000条数据
前端·css
kyriewen9 小时前
别再这样写条件渲染了——你的React组件里藏着这5种定时炸弹
前端·javascript·react.js
IT_陈寒10 小时前
Redis缓存击穿把我坑惨了,原来这样设过期时间才靠谱
前端·人工智能·后端
用户9385156350710 小时前
从"坐电梯"到"前端路由"——深入理解 Hash 路由原理
前端·typescript·全栈