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. 三法则:写其一,必写其二(析构 / 拷贝 / 赋值)

相关推荐
KuaCpp1 小时前
C++新特性学习
c++·学习
墨染千千秋2 小时前
C/C++ Keywords
c语言·c++
ximu_polaris2 小时前
设计模式(C++)-行为型模式-中介者模式
c++·设计模式·中介者模式
iDao技术魔方2 小时前
DeepSeek TUI:原生 Rust 打造的终端 AI 编码 Agent
开发语言·人工智能·rust
jghhh012 小时前
认知无线电中基于能量检测的双门限频谱感知的 MATLAB 仿真
开发语言·matlab
Mr数据杨2 小时前
【Codex】用教案主体模块沉淀标准化教学设计内容
java·开发语言·django·codex·项目开发
wangbing11252 小时前
踩坑:el8应用装在el9上
开发语言·后端·ruby
Andya_net3 小时前
Java | Java内存模型JMM
java·开发语言
froginwe113 小时前
SQL LIKE 操作符详解
开发语言