c++中接口需用仅含public纯虚函数的抽象基类实现,virtual和=0不可省略,析构函数必须virtual;虚继承不适用于接口;推荐使用智能指针传递接口。

为什么 C++ 没有 interface 关键字,但你仍要模拟接口
因为 C++ 标准直到 C++20 才引入 concept(概念),而它不是接口的替代品;真正的运行时多态接口,必须靠纯虚函数类(abstract class)来承载。虚基类(virtual base class)本身和“定义接口”无关——它只解决菱形继承中的重复子对象问题,误用反而会让接口语义变模糊。
所以:你要的不是虚基类,是「只含纯虚函数的抽象基类」,且所有函数都应声明为 public、virtual、= 0,析构函数必须是 virtual。
- 不写
virtual析构函数 → 派生类对象通过基类指针 delete 时,派生部分不析构,内存泄漏或未定义行为 - 把函数写成
protected或private→ 用户无法调用,违背接口“供外部使用”的本质 - 在接口类里加数据成员或非纯虚函数 → 它就不再是纯粹的契约,而是具体实现的混杂体
class 声明接口时,哪些修饰符不能省
一个被当作接口的类,每个成员函数声明中,virtual 和 = 0 是硬性要求;public 访问限定符也必须显式写出——C++ 默认是 private,漏写就等于把接口函数锁死了。
示例:
立即学习“C++免费学习笔记(深入)”;
class Drawable {
public:
virtual ~Drawable() = default; // 必须 virtual,即使 default
virtual void draw() = 0; // virtual + = 0 缺一不可
virtual void resize(float scale) = 0;
};-
~Drawable()不写virtual→ 多态销毁失效 -
draw()漏掉virtual→ 派生类重写后,通过基类指针调用仍走基类空实现(如果有)或报错 -
resize()忘了= 0→ 这个类不再是抽象类,用户能直接实例化,失去接口约束力
继承多个接口时,虚继承(virtual)要不要加
不需要。接口类之间无数据成员、无构造逻辑,彼此正交,多重继承它们不会引发二义性或重复子对象问题。加 virtual 反而增加虚表开销,且让继承关系图人为复杂化。
正确做法是普通 public 继承:
class Clickable : public virtual Drawable { /* ... */ }; // ❌ 错误:虚继承接口无意义class Clickable : public Drawable, public Focusable { /* ... */ }; // ✅ 正确- 只有当两个父类共同继承自同一个有状态的基类(比如
Shape含color成员),才需要虚继承避免重复 - 接口类(如
Drawable、Focusable)不含数据、不参与构造,虚继承只拖慢编译和运行时查表 - 若真出现函数名冲突(比如两个接口都有
handle()),说明设计有问题——接口职责应正交,冲突意味着抽象粒度错了
用 std::unique_ptr<interface></interface> 还是裸指针传接口
优先用 std::unique_ptr<drawable></drawable> 或 std::shared_ptr<drawable></drawable>,而不是 Drawable* 或 Drawable&。裸指针不表达所有权,调用方无法判断是否该释放、能否为空;引用又强制非空,灵活性差。
-
void render(std::unique_ptr<drawable> obj)</drawable>→ 明确表示“我接管生命周期”,调用方必须 move 进来 -
void draw(const Drawable& obj)→ 仅读取,不涉所有权,适合临时使用 -
void set_callback(Drawable* cb)→ 危险!无法保证cb生命周期长于持有者,易悬空
真正难处理的是跨模块/跨 DLL 的接口传递:此时 RTTI 和虚表布局可能不一致,dynamic_cast 失效,建议用 PIMPL 或 C 风格函数指针封装,而非强依赖 C++ 虚函数机制。










