C++面试7——继承与多态
在C++面试中,继承与多态是考察面向对象理解深度的核心考点。以下是深入浅出的解析,包含关键概念、技术细节和面试常见陷阱:
继承(Inheritance)
核心概念
- \"is-a\"关系:派生类(Derived)是基类(Base)的特殊化(如
Car
继承Vehicle
) - 代码复用:派生类继承基类的成员(数据+方法)
- 访问控制:
public
继承:基类public→派生public,protected→protectedprotected
继承:基类public/protected→派生protectedprivate
继承:基类所有成员→派生private(极少用)
面试高频坑点
-
切片问题(Slicing)
class Base { /*...*/ };class Derived : public Base { /*...*/ };Derived d;Base b = d; // 对象切片!丢失Derived特有成员
解决方案:使用指针/引用
Base& b = d;
-
构造函数调用顺序
class Derived : public Base {public: Derived() : Base() {} // 必须显式调用基类有参构造};
- 构造顺序:基类→成员对象→自身
- 析构顺序:自身→成员对象→基类
-
名字隐藏(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)
核心概念
- 动态绑定:运行时根据对象实际类型调用函数
- 实现机制:虚函数表(vtable)+ 虚指针(vptr)
- 每个含虚函数的类有自己的vtable
- 对象创建时vptr指向对应vtable
- 关键语法:
class Shape {public: virtual double area() const = 0; // 纯虚函数→抽象类 virtual ~Shape() {} // 虚析构!必须!};class Circle : public Shape {public: double area() const override { /*...*/ } // override确保正确重写};
面试致命陷阱
-
忘记虚析构函数
Base* p = new Derived();delete p; // 若~Base()非虚→仅调用~Base()!内存泄漏!
规则:基类有虚函数时,析构函数必须为虚
-
虚函数默认参数静态绑定
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版)
解决:避免在虚函数中使用默认参数
-
构造函数/析构函数中调用虚函数
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 组合:面试灵魂拷问
黄金法则:
- 需要多态 → 用继承
- 只需复用代码 → 用组合
- 避免多继承(菱形继承问题)
面试实战技巧
-
必考问题:
- “虚函数实现原理?” → 答vptr+vtable
- “为什么需要虚析构?” → 举例内存泄漏场景
- “override关键字作用?” → 防止签名错误隐藏函数
-
代码题陷阱:
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
-
高级话题:
- 动态转换:
dynamic_cast(basePtr)
(需RTTI) - final关键字:禁止派生/重写
class NoDerived final { /*...*/ }; // 禁止继承class Base {public: virtual void lock() final; // 禁止重写};
- 动态转换:
总结:面试回答模板
\"C++多态通过虚函数机制实现,核心是运行时动态绑定。使用时需注意:
- 基类声明虚析构函数防止资源泄漏
- 使用override确保正确重写虚函数
- 避免在构造/析构中调用虚函数
- 优先用组合代替继承除非需要多态
继承应严格满足Liskov替换原则:派生类必须能替代基类工作\"
掌握这些要点,面试官会认为你真正理解C++面向对象的精髓!