> 技术文档 > C++面试7——继承与多态

C++面试7——继承与多态

在C++面试中,继承与多态是考察面向对象理解深度的核心考点。以下是深入浅出的解析,包含关键概念、技术细节和面试常见陷阱:


继承(Inheritance)

核心概念
  1. \"is-a\"关系:派生类(Derived)是基类(Base)的特殊化(如Car继承Vehicle
  2. 代码复用:派生类继承基类的成员(数据+方法)
  3. 访问控制
    • public继承:基类public→派生public,protected→protected
    • protected继承:基类public/protected→派生protected
    • private继承:基类所有成员→派生private(极少用)
面试高频坑点
  1. 切片问题(Slicing)

    class Base { /*...*/ };class Derived : public Base { /*...*/ };Derived d;Base b = d; // 对象切片!丢失Derived特有成员

    解决方案:使用指针/引用 Base& b = d;

  2. 构造函数调用顺序

    class Derived : public Base {public: Derived() : Base() {} // 必须显式调用基类有参构造};
    • 构造顺序:基类→成员对象→自身
    • 析构顺序:自身→成员对象→基类
  3. 名字隐藏(Name Hiding)

    class Base {public: void func(int) {}};class Derived : public Base {public: void func() {} // 隐藏Base::func(int)!};Derived d;d.func(1); // 错误!被隐藏d.Base::func(1); // 正确但丑陋

    解决:使用using Base::func;引入基类函数


多态(Polymorphism)

核心概念
  1. 动态绑定:运行时根据对象实际类型调用函数
  2. 实现机制:虚函数表(vtable)+ 虚指针(vptr)
    • 每个含虚函数的类有自己的vtable
    • 对象创建时vptr指向对应vtable
  3. 关键语法
    class Shape {public: virtual double area() const = 0; // 纯虚函数→抽象类 virtual ~Shape() {}  // 虚析构!必须!};class Circle : public Shape {public: double area() const override { /*...*/ } // override确保正确重写};
面试致命陷阱
  1. 忘记虚析构函数

    Base* p = new Derived();delete p; // 若~Base()非虚→仅调用~Base()!内存泄漏!

    规则:基类有虚函数时,析构函数必须为虚

  2. 虚函数默认参数静态绑定

    class Base {public: virtual void print(int x = 1) { cout << x; }};class Derived : public Base {public: void print(int x = 2) override { cout << x; }};Base* p = new Derived();p->print(); // 输出1!默认参数静态绑定(Base版)

    解决:避免在虚函数中使用默认参数

  3. 构造函数/析构函数中调用虚函数

    class Base {public: Base() { callVirt(); } // 危险! virtual void callVirt() { cout << \"Base\"; }};class Derived : public Base {public: void callVirt() override { cout << \"Derived\"; }};Derived d; // 输出\"Base\"!构造期间对象类型是Base

    原理:构造/析构期间虚函数机制未完全生效


继承 vs 组合:面试灵魂拷问

场景 继承 组合(包含对象成员) 关系 “is-a” (Car is a Vehicle) “has-a” (Car has an Engine) 耦合度 高耦合 低耦合 复用 白盒复用(了解基类实现) 黑盒复用(仅使用接口) 典型误用 为复用公共代码而继承(应组合) 需要多态时未用继承

黄金法则

  • 需要多态 → 用继承
  • 只需复用代码 → 用组合
  • 避免多继承(菱形继承问题)

面试实战技巧

  1. 必考问题

    • “虚函数实现原理?” → 答vptr+vtable
    • “为什么需要虚析构?” → 举例内存泄漏场景
    • “override关键字作用?” → 防止签名错误隐藏函数
  2. 代码题陷阱

    class A { public: virtual void f() { cout << \"A\"; }};class B : public A {public: void f() { cout << \"B\"; }};A* pa = new B();pa->f(); // 问输出?→ B(多态正确)delete pa; // 问是否安全?→ 不安全!若~A()非虚则UB
  3. 高级话题

    • 动态转换:dynamic_cast(basePtr)(需RTTI)
    • final关键字:禁止派生/重写
    class NoDerived final { /*...*/ }; // 禁止继承class Base {public: virtual void lock() final; // 禁止重写};

总结:面试回答模板

\"C++多态通过虚函数机制实现,核心是运行时动态绑定。使用时需注意:

  1. 基类声明虚析构函数防止资源泄漏
  2. 使用override确保正确重写虚函数
  3. 避免在构造/析构中调用虚函数
  4. 优先用组合代替继承除非需要多态

继承应严格满足Liskov替换原则:派生类必须能替代基类工作\"

掌握这些要点,面试官会认为你真正理解C++面向对象的精髓!