类默认成员函数 & 内存布局
// C++ 编译器默认生成的 6 个函数 (C++11)
class MyClass {
MyClass(); // 默认构造函数
MyClass(const MyClass&); // 拷贝构造
MyClass(MyClass&&); // 移动构造 (C++11)
MyClass& operator=(const MyClass&); // 拷贝赋值
MyClass& operator=(MyClass&&); // 移动赋值 (C++11)
~MyClass(); // 析构函数
};
// 对象内存布局 (有虚函数时)
// ┌─────────────────────────────┐
// │ vptr (虚表指针, 8 bytes) │ ← 对象首地址
// ├─────────────────────────────┤
// │ 成员变量 (按声明顺序) │
// └─────────────────────────────┘
💡 static 成员变量属于类,不属于任何实例,所有对象共享同一份。访问方式:ClassName::member 或 obj.member
虚函数 & 多态机制
class Base {
public:
virtual void speak() { cout << "Base"; } // 虚函数
virtual void pure() = 0; // 纯虚函数 → 抽象类
void normal() {} // 普通函数,不参与多态
};
class Derived : public Base {
public:
void speak() override { cout << "Derived"; } // 覆盖(不加virtual也生效)
void pure() override {} // 必须实现,否则仍为抽象类
};
// 多态调用链:
Base* p = new Derived();
p->speak(); // → vptr → vtable[1] → Derived::speak ✓ 运行时多态
⚠️ 为什么不能所有函数都设虚?1) 每个类多一个vptr(8B) 2) 每次调用多一次间接寻址 3) 构造函数不能为虚(对象未构造时vptr不存在)
三种继承 & 析构函数
// 继承方式对比
class B { public: int pub; protected: int pro; private: int pri; };
class D1 : public B {}; // pub→pub, pro→pro, pri→不可访问
class D2 : protected B {}; // pub→pro, pro→pro, pri→不可访问
class D3 : private B {}; // pub→pri, pro→pri, pri→不可访问
// 为什么基类析构必须为虚?
class Base { public: virtual ~Base() {} }; // ✓ 正确
// delete base_ptr 时,若析构非虚 → 只调 Base::~Base → 内存泄漏!
💡 子类覆盖父类virtual函数时,加不加virtual关键字都能实现多态(C++标准规定覆盖自动继承虚属性)。子类对象内存中包含父类的所有非静态成员(含private,只是无法直接访问)。
插件化推理框架中的应用
// 插件化推理框架核心设计
class IInferencePlugin { // 抽象接口
public:
virtual ~IInferencePlugin() = default;
virtual Tensor forward(const Tensor& input) = 0;
virtual string name() const = 0;
};
// 各后端实现为动态库 (.so/.dll)
class CUDAPlugin : public IInferencePlugin { ... };
class ONNXPlugin : public IInferencePlugin { ... };
// 框架通过 vptr/vtable 实现运行时绑定:
IInferencePlugin* plugin = loadPlugin("cuda_backend.so");
plugin->forward(data); // 通过虚表分发到具体实现
🔑 虚表机制使框架无需在编译期知道具体实现 → 热插拔、动态加载、ABI兼容性的基础