c++基础知识

c++基础知识

c++三种智能指针

**unique_ptr **是独占所有权,不能拷贝,只能移动;
**shared_ptr **是共享所有权,用引用计数管理资源;
**weak_ptr **是弱引用,不参与引用计数,用来打破 shared_ptr 的循环引用。

怎么解决循环引用

循环引用产生的原因是 shared_ptr 是强引用,两个对象互相持有 strong 引用时,
它们的引用计数都不会降到 0,从而导致内存泄漏。

解决办法是把其中一个 shared_ptr 换成 weak_ptr。
weak_ptr 是弱引用,不增加引用计数,不参与对象的生命周期管理,
从而打破强引用环,引用计数能正常归零。
使用 weak_ptr 时通过 lock() 获取 shared_ptr 来安全访问对象。


explicit的主要作用是防止构造函数或者转化函数在不合适的条件下进行隐式的转化。


#pragma pack(1) 内存对齐


C++ 有四种显式转换:

static_cast:编译期类型转换,安全性中等,用于基本类型、父子类向上转,
向下转不做检查。

dynamic_cast:运行时类型检查,安全性最高,用于多态类向下转,
失败返回 nullptr。

const_cast:修改 const/volatile 属性,不改变类型本质,
不能用来改变真正常量的内存。

reinterpret_cast:位级别重新解释,非常危险,用于底层指针、整数转换。


C++ 的多态通过虚函数实现。
编译器为包含虚函数的类生成虚函数表(vtable),对象中保存一个 vptr 指向对应的虚表。
调用虚函数时,根据 vptr 找到实际要执行的函数地址,实现运行期动态派发。

父类指针指向子类对象时,由于 vptr 指向子类的虚表,因此调用的是子类方法。
析构函数需要是 virtual 才能正确删除子类对象。

那为啥构造函数不能是虚函数,析构函数要是虚函数

构造函数不能是虚函数,因为构造流程必须先执行基类构造函数,再执行派生类构造函数。
在执行基类构造时,对象的 vptr 还指向基类的 vtable,对象还不是派生类,
无法通过虚函数机制动态派发到派生类的构造函数。

如果构造函数是虚函数,基类构造阶段会试图根据 vptr 调用派生类构造,
但此时派生类部分还未初始化,vptr 也未写入,调用流程会崩溃。

因此构造函数不允许是虚函数。

析构函数必须是虚函数,因为当我们用 Base* 指向 Derived 并 delete 时,
如果析构函数不是虚的,就只会调用 Base 的析构函数,不会调用 Derived 的析构函数,
导致子类资源泄漏。

把析构函数设为 virtual,delete 时会通过 vptr 动态绑定,
根据对象的真实类型调用 Derived::Derived(),然后再调用 Base::Base(),
确保整个对象正确释放。

菱形继承和怎么解决?

菱形继承是指多个中间类同时继承同一个基类,而最终派生类又多重继承这些中间类,
导致基类在派生类中出现多份副本,造成成员访问二义性和内存冗余。

解决方法是使用虚继承,即让中间类 virtual public Base。
这样所有派生类将共享同一份 Base 子对象,从而避免重复继承和二义性。