C++ 继承

在 C++ 中,继承(inheritance)是一种面向对象编程的机制,允许你在已有类(基类/父类)的基础上派生出新类(派生类/子类),从而复用、扩展或修改已有行为。下面分几个方面介绍继承的要点与用法。


1. 基本语法

// 基类
class Base {
public:
    void    foo()   { /*…*/ }
    virtual void bar() { /*…*/ }
protected:
    int data_;
};

// 派生类,public 继承
class Derived : public Base {
public:
    void baz() { /*…*/ }
    void bar() override { /* 重写基类的 virtual bar() */ }
};
  • class D : public B 表示 公有继承(public inheritance),最常用。
  • 还可用 protected 或 private 继承,分别将基类的公有和保护成员降为派生类的保护或私有成员(不常用)。

2. 访问控制与继承方式

继承方式基类的 public → 派生基类的 protected → 派生派生对外可见性
publicpublicprotected派生对外可访问 public 成员
protectedprotectedprotected派生的所有继承成员都 protected
privateprivateprivate派生的所有继承成员都 private

3. 构造与析构

  • 构造顺序:先调用基类构造,再调用派生类构造。
  • 析构顺序:先调用派生类析构,再调用基类析构。
  • 在派生类构造函数的初始化列表中,可显式调用基类构造:class Derived : public Base { public: Derived(int x, int y) : Base(x) // 调用 Base(int) , member_(y) {} private: int member_; };

4. 多重继承与菱形继承

4.1 多重继承

class A { /*…*/ };
class B { /*…*/ };
class C : public A, public B { /*…*/ };
  • C 同时继承自 A 和 B,但会分别包含两份 A、B 的子对象。

4.2 菱形继承与虚继承

当多个派生路径导致“钻石”结构,普通多重继承会引入基类多份子对象,可能造成二义性:

class A { /*…*/ };
class B : public A { /*…*/ };
class C : public A { /*…*/ };
class D : public B, public C { /*…*/ };

// D 中有两份 A 子对象:B::A 和 C::A

使用 虚继承(virtual inheritance)可保证只有一份共享的 A:

class B : virtual public A { /*…*/ };
class C : virtual public A { /*…*/ };
class D : public B, public C { /*…*/ };

5. 覆盖与重载

  • 重载(overload)是指同一类中同名函数参数列表不同。
  • 覆盖(override)是派生类重写基类的虚函数。使用 override 关键字可让编译器检查签名是否一致:struct Base { virtual void f(int); }; struct Derived : Base { void f(int) override; // 正确覆盖 void f(double) override; // 错误:没有对应基类重载可覆盖 };

6. 多态与虚函数

  • 基类将函数声明为 virtual,允许派生类提供不同实现。
  • 通过基类指针或引用调用虚函数时,运行期(RTTI)会动态绑定到派生类版本,实现 动态多态Base* p = new Derived; p->bar(); // 调用 Derived::bar()
  • 别忘了给基类声明虚析构函数,避免通过基类指针删除派生对象时发生资源泄漏:struct Base { virtual ~Base() = default; };

7. 禁止继承与最终继承

  • C++11 起可用 final 修饰,防止某个类被进一步派生,或某个虚函数被重写:class Base final { /*…*/ }; // Base 不能被继承 class B { virtual void f() final; // f() 不能被覆盖 };

8. 对象切片(Object Slicing)

如果用基类对象而非指针/引用来接收派生类实例,会发生对象切片,派生类的扩展部分被截断:

Derived d;
Base b = d;     // 切片:b 只保留 Base 部分
  • 避免将派生对象直接赋值给基类对象,使用指针或引用来保留完整多态性。

小结

  • 通过 公有继承 复用并扩展基类行为,使用虚函数实现运行期多态。
  • 理解 访问控制构造/析构顺序虚继承(解决菱形问题)、对象切片 等细节,才能设计出安全、可维护的类层次。
  • 使用 overridefinal、虚析构等现代特性,可让继承体系更健壮、错误更易发现。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注