继承vs虚拟继承

虚拟继承和普通继承在C++中都是实现类与类之间的继承关系的方式,但它们在实现细节和用途上有一些重要区别。

1. 普通继承(非虚拟继承)

特点

  • 普通继承是C++中默认的继承方式,派生类对基类的继承没有特别的共享机制。

  • 每个派生类会各自拥有基类的独立副本。如果存在多重继承并且派生类从同一个基类间接继承时,可能会产生多个基类副本(菱形继承问题)。

示例

class A {
public:
    int value;
    A() : value(10) {}
};

class B : public A { };
class C : public A { };
class D : public B, public C { };

在这种结构中,D类包含两个A类的副本:一个从B继承而来,另一个从C继承而来。

优缺点

  • 优点:结构简单,不会增加额外的内存或性能开销。

  • 缺点:可能导致菱形继承问题,使派生类中存在多个基类副本,造成内存浪费和访问冲突。

2. 虚拟继承(Virtual Inheritance)

特点

  • 虚拟继承是一种解决多重继承中菱形继承问题的方式。

  • 通过在基类前加上virtual关键字,可以告诉编译器在派生类中只保留一个共享的基类实例。

  • 虚拟继承可以确保多条继承路径只会产生一个基类实例,从而避免重复实例。

示例

class A {
public:
    int value;
    A() : value(10) {}
};

class B : virtual public A { };  // 虚拟继承
class C : virtual public A { };  // 虚拟继承
class D : public B, public C { };

在这种结构中,D类中只有一个A的共享实例,从而避免了二义性问题。

优缺点

  • 优点:解决了菱形继承导致的冗余和二义性问题。

  • 缺点:虚拟继承增加了内存开销和少量的运行时开销,因为编译器需要额外的指针来管理虚基类实例。

二者的对比总结

特点

普通继承

虚拟继承

基类实例

每条继承路径都有一个独立实例

所有派生类共享同一个基类实例

使用场景

单一继承、非菱形继承

菱形继承

内存和性能

无额外开销

增加少量的内存和运行时开销

访问冲突

可能出现多基类访问冲突

避免多基类访问冲突

总之,虚拟继承是普通继承的扩展,专门用于解决多重继承中的菱形继承问题,确保继承关系的简洁性和一致性。

Last updated