C++第三讲:类和对象(中)

C++第三讲:类和对象(中)

这一章是C++ 面向对象最核心、最难、面试必考的内容。


一、6 个默认成员函数(必须背)

我们不写 ,编译器自动生成的函数,一共 6 个:

  1. 构造函数 ------ 初始化对象

  2. 析构函数 ------ 释放资源

  3. 拷贝构造 ------ 用一个对象初始化新对象

  4. 赋值重载 ------ 两个已存在对象互相赋值

  5. 普通取地址重载

  6. const 取地址重载

重点:前 4 个必考,后两个几乎不用自己写。


二、构造函数(初始化)

1. 作用

代替Init()对象创建时自动调用,完成初始化。

2. 特征

  • 函数名 == 类名

  • 无返回值(不写 void)

  • 可重载

  • 不写则编译器生成无参默认构造

  • 无参、全缺省、编译器生成的,都叫默认构造,只能存在一个

3. 写法

cpp 复制代码
class Date
{
public:
    // 无参默认构造
    Date()
    {
        _year = 1;
        _month = 1;
        _day = 1;
    }
​
    // 带参构造
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
​
    // 全缺省构造(和无参构造只能留一个)
    // Date(int year=1, int month=1, int day=1) {}
​
private:
    int _year;
    int _month;
    int _day;
};

4. 使用

cpp 复制代码
Date d1;        // 调用默认构造
Date d2(2025,5,1); // 调用带参构造
// Date d3();   ❌ 错误!这是函数声明,不是对象

5. 编译器默认构造行为

  • 内置类型(int/char/ 指针):不初始化,值随机

  • 自定义类型(类对象):调用它的默认构造


三、析构函数(资源清理)

1. 作用

代替Destroy()对象生命周期结束时自动调用,释放资源。

2. 特征

  • 名字:~类名

  • 无参、无返回值

  • 一个类只能有一个,不能重载

  • 不写则编译器自动生成

3. 什么时候必须自己写?

类里申请了动态内存(malloc/new),必须自己写析构释放!

比如 Stack、Queue、List。

4. 写法

cpp 复制代码
class Stack
{
public:
    Stack(int n=4)
    {
        _a = (int*)malloc(sizeof(int)*n);
        _top = 0;
        _capacity = n;
    }
​
    // 析构函数
    ~Stack()
    {
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }
​
private:
    int* _a;
    size_t _top;
    size_t _capacity;
};

四、拷贝构造(重中之重!)

1. 作用

一个已存在的对象 ,创建一个新的一模一样的对象

2. 格式(必须背)

cpp 复制代码
类名(const 类名& 另一个对象)

为什么必须用引用?

传值会引发无穷递归

因为传参本身就要拷贝,拷贝又要调用拷贝构造。

3. 浅拷贝 vs 深拷贝

浅拷贝(编译器默认生成)

  • 只拷贝值

  • 指针拷贝后指向同一块内存

  • 析构时会重复释放同一块地址 → 崩溃!

深拷贝(自己实现)

  • 重新开一块同样大小的空间

  • 把数据拷贝过去

  • 两个对象指针指向不同内存,安全

4. Stack 深拷贝写法

cpp 复制代码
Stack(const Stack& st)
{
    // 1. 开新空间
    _a = (int*)malloc(sizeof(int)*st._capacity);
    // 2. 拷贝数据
    memcpy(_a, st._a, sizeof(int)*st._top);
    _top = st._top;
    _capacity = st._capacity;
}

5. 调用拷贝构造的场景

  1. Date d2(d1);

  2. Date d2 = d1;

  3. 函数传值传参

  4. 函数传值返回


五、赋值运算符重载(= 号)

1. 作用

两个已经存在的对象之间互相赋值。

2. 和拷贝构造的区别

  • 拷贝构造:创建新对象时初始化

  • 赋值重载:两个老对象互相赋值

cpp 复制代码
Date d1(2025,5,1);
Date d2 = d1; // 拷贝构造
Date d3;
d3 = d1;      // 赋值重载

3. 必须重载为成员函数

格式:

cpp 复制代码
Date& operator=(const Date& d)
{
    if (this != &d) // 防止自己给自己赋值
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    return *this; // 支持连续赋值 a=b=c
}

4. 浅拷贝问题

和拷贝构造一样:

  • 有指针 / 资源 → 必须自己写深拷贝

  • 无资源 → 用编译器默认的就行


六、运算符重载(通用规则)

1. 什么是运算符重载

让运算符支持自定义类型对象运算。

2. 规则

  • 不能创造新运算符

  • 优先级 / 结合性不变

  • 作为成员函数时,参数个数 = 操作数 - 1(this 占了一个)

3. 不能重载的 5 个(必考)

cpp 复制代码
.      .*     ::     sizeof     ?:

4. 前后置 ++ 区分

  • 前置:Date& operator++()

  • 后置:Date operator++(int)(int 是占位参数)

5. <<和>> 必须重载为全局函数

因为cout要在左边,this会抢占左边位置。

通常配合友元使用。


七、const 成员函数(超级高频考点)

1. 写法

函数后面加 const:

cpp 复制代码
void Print() const

2. 作用

修饰this 指针,让 this 变成:

cpp 复制代码
const Date* const this

意思是:在函数里不能修改成员变量

3. 使用规则

  • const 对象 只能调用 const 成员函数

  • 非 const 对象 可以调用 const 函数(权限缩小)


八、取地址重载

  • 普通:Date* operator&()

  • const:const Date* operator&() const

99% 情况不用自己写,编译器默认生成的就够用。


九、一张表总结 4 大核心默认函数

函数 作用 何时需要自己实现
构造 初始化 想自定义初始值
析构 释放资源 有动态内存
拷贝构造 对象拷贝初始化 有动态内存(深拷贝)
赋值重载 对象赋值 有动态内存(深拷贝)

十、快速判断口诀(超好用)

  1. 没指针、没资源 → 全用编译器默认的,啥也不用写

  2. 有指针、有 malloc → 必须写:析构、拷贝构造、赋值重载

  3. 三法则:写其一,必写其二(析构 / 拷贝 / 赋值)

相关推荐
优橙教育2 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
同勉共进3 小时前
记一例 vibe coding + gcc bug 导致的线程池死锁问题
c++·线程池·gcc·死锁·vibe coding
我叫洋洋3 小时前
C ++ [ hello world ]
c语言·c++·算法
SeaTunnel3 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
碎光拾影4 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
Marst Code4 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
Miao121315 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
CRMEB系统商城6 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
王维同学6 小时前
[自学][Windows C++]RunOnceEx 注册表分组键的安全遍历
c++·windows·安全·开源
keyipatience7 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu