Cpp

Tecy 发布于 2025-03-27 101 次阅读


封装

将具体实现过程和数据封装成一个类,只能通过接口进行访问。
作用:保护或防止代码在无意之中被破坏,保护类中的成员。

继承

子类继承父类的特征和行为,复用了基类的全体数据成员函数(基类私有成员可被继承,但是无法被访问),其中构造函数、析构函数、友元函数、静态数据成员、静态成员函数都不能被继承。

final 标识符

struct test final {};

放在类的后面表示该类无法被继承,也就是阻止了从类的继承;
放在虚函数后面该虚函数无法被重写,表示阻止虚函数的重载。

多态

不同继承类的对象对同一消息做出不同的响应,基类的指针指向或绑定到派生类的对象,使得基类指针呈现不同的表现形式。

多态原理

  • 动态多态:利用虚函数实现运行时的多态,利用虚函数表调用对应的表。
  • 静态多态:通过函数重载来实现。

虚函数

虚函数是在基类中使用关键字 virtual 声明的成员函数,它允许派生类对其进行重写(Override),实现运行时多态。

当通过基类指针或引用调用虚函数时,实际调用的是对象类型对应的派生类中的函数,这个过程称为动态绑定(Dynamic Binding)。

final 标识符

struct test final {
    virtual void mk() final {}; 
};

放在类的后面表示该类无法被继承,也就是阻止了从类的继承;
放在虚函数后面该虚函数无法被重写,表示阻止虚函数的重载。

override 标识符

class basic {
    virtual void mk() {};
};

struct test : basic {
    virtual void mk() override {}; 
};

保证在派生类中声明的重载函数,与基类的虚函数有相同的签名。

虚函数原理

类的虚函数表:

  • 当一个类中包含虚函数时,编译器会为该类生成虚函数表,表中保存该类包含的虚函数的地址
  • 一个包含虚函数的类,至少有1张虚函数表
  • 一个普通类继承了n个有虚函数的基类,就有n张虚函数表。
  • 类中重写父类的虚函数A,那自己虚函数表中将A对应的地方,替换成重写后的虚函数的地址。
    对象的虚函数表指针:
  • 当一个类中包含虚函数时,该类的对象将会拥有虚函数表指针指向该类的虚函数表
  • 类有n张虚函数表,类的对象就有n个虚指针,每个指针指向1张虚函数表

对象 $\stackrel{虚函数表指针}{\rightarrow}$ 虚函数表 $\stackrel{虚函数指针}{\rightarrow}$ 虚函数。

  • 虚函数表:在编译时生成,存储在只读数据段。
  • 虚函数表指针:在对象创建时生成,位置在对象的头部,根据对象创建方式存储在堆或栈上。

纯虚函数

class A {  
    virtual void example() = 0; // 纯虚函数
}

纯虚函数是虚函数的一种特殊形式,它的语法是在函数声明后加上’=0’。纯虚函数只有声明没有实现,含有纯虚函数的类称为抽象类,不能被实例化。它的派生类如果想被实例化,就必须实现所有的纯虚函数。

哪些函数不能是虚函数?

  • 构造函数:执行构造函数前虚表指针尚未初始化,无法正确调用构造函数(析构函数可以是虚函数)。
  • 静态函数:静态函数不属于对象属于类,静态成员函数没有this指针,因此静态函数设置为虚函数没有任何意义。
  • 友元函数,友元函数不属于类的成员函数,不能被继承。对于没有继承特性的函数没有虚函数的说法。
  • 普通函数,普通函数不属于类的成员函数,不具有继承特性,因此普通函数没有虚函数。

智能指针

auto_ptr

已弃用。

unique_ptr

std::unique_ptr 是独占所有权的智能指针,一个对象只能被一个 std::unique_ptr 管理,不能共享所有权。

主要用途:

  1. 自动释放资源:当 std::unique_ptr 超出作用域时,会自动释放所管理的资源。
  2. 独占所有权:确保同一资源不会被多个指针操作,避免潜在的内存问题。
  3. 高效传递所有权:通过 std::move 可以将资源所有权转移。

实现要点:

  • 成员变量:包含一个裸指针 T* ptr 和可定制的删除器。
  • 禁用拷贝:通过 = delete 或私有化拷贝构造函数和赋值运算符,禁止复制语义。
  • 支持移动:移动构造函数和赋值操作符转移所有权,原指针置 nullptr
  • 析构释放:析构时调用删除器(默认 delete ptr)释放资源。

shared_ptr

std::shared_ptr 是具有共享所有权的智能指针,多个 std::shared_ptr 可以同时管理同一资源,采⽤引用计数器,当计数为0的时候会自动的释放动态分配的资源

主要用途:

  1. 共享资源的生命周期管理:适用于多个对象需要访问和管理同一资源的场景。
  2. 引用计数:内部维护一个引用计数,记录资源被引用的次数。
  3. 线程安全:引用计数是线程安全的,多线程读写不安全

实现要点:

  • 控制块:包含强引用计数(use_count)、弱引用计数(weak_count)、原始指针和删除器。
  • 原子操作:引用计数的增减是线程安全的(如 std::atomic)。
  • 构造/拷贝:新实例递增强引用计数;析构时递减,计数归零则释放资源。
  • 循环引用解决:需结合 weak_ptr 打破循环。

weak_ptr

std::weak_ptr 是一种弱引用的智能指针,它不会增加资源的引用计数,通常与 std::shared_ptr 配合使用。

主要用途:

  1. 解决循环引用问题:避免 std::shared_ptr 之间的循环引用导致资源无法释放。
  2. 观察资源状态:可以安全地观察 std::shared_ptr 管理的资源是否仍然存在。

实现要点:

  • 依赖控制块:与 shared_ptr 共享同一控制块,但仅操作弱引用计数。
  • 提升为 shared_ptr:通过 lock() 方法检查强引用计数,若有效则创建新 shared_ptr
  • 控制块生命周期:强引用计数归零时释放对象,弱引用计数归零时释放控制块。

左值

可以获取它的地址。
可以修改(非 const)。

右值

右值不能取地址。
不能修改。

引用

引用是对被引用的对象取一个别名。

右值引用

右值引用是为一个临时变量取别名,它只能绑定到一个临时变量或表达式(将亡值)上。
支持移动语义,右值引用可以绑定到临时对象、表达式等右值上,这些右值在生命周期结束后就会被销毁,因此可以在右值引用中窃取其资源,从而避免昂贵的复制操作,实现高效的移动语义。

const

  • 修饰变量:该变量不能被改变。
  • 修饰成员函数:函数不能改变对象的值。
  • 修饰指针:const 修饰指针指向的内容,则内容为不可变量,const 修饰指针,则指针为不可变量。

new / malloc

  • new 自动申请大小合适的内存,返回的是对象类型的指针,类型严格与对象匹配,申请失败抛出异常。
  • malloc 手动指定内存大小,返回 void*,需要类型转换,申请失败返回 NULL。