C++ 为什么不要多重继承?

多重继承有何不妥?

多重继承指的是某个类同时继承了两个或以上的其他类。那么多重继承存在着什么问题呢?

class Machine
{
public:
    virtual ~Machine() {}
    Machine() { std::cout << "machine \n"; }
};

class Printer : public Machine
{
public:
    Printer() : Machine() {}
};

class Scanner : public Machine
{
public:
    Scanner() : Machine() {}
};

class PrinterScanner : public Printer, public Scanner
{
public:
    PrinterScanner() : Printer(), Scanner() {}
};

int main()
{
    PrinterScanner ps;
}

运行代码,输出结果:

machine
machine

我们可以看到 Machine 的构造函数被调用了两次。其实这也很好理解,因为 PrinterScanner 同时继承了 PrinterScanner。而 PrinterScanner 又同时单一继承了 Machine,自然就会构造出两个 Machine 子对象。虽然问题不大,但重复的子对象略显多余,有没有办法可以让最 PrinterScanner "共享"一个 Machine 子对象呢?有。


继承也可以虚拟化?

在声明继承的时候加上 virtual 关键字,即虚拟继承。

class Machine { /* ... */ };

class Printer : public virtual Machine
{
public:
    Printer() : Machine() {}
};

class Scanner : public virtual Machine
{
public:
    Scanner() : Machine() {}
};

class PrinterScanner : public Printer, public Scanner
{
public:
    PrinterScanner() : Printer(), Scanner() {}
};

int main()
{
    PrinterScanner ps;
}

运行代码:

machine

这次 Machine 的构造函数只被调用了一次。


虚拟继承也有自己的问题

引入虚拟基类解决了重复子对象问题。但是不是多重继承就不会衍生出其他问题?继承意味着,当一个基类的结构发生变化的时候,继承这个类的其他类也会受到影响。如果我们给 Machine 这个类加入一个虚函数,看看其他类的反应如何。

class Machine
{
public:
    Machine() { std::cout << "machine \n"; }
    virtual void run() = 0;
};

class Printer : public Machine
{
public:
    Printer() : Machine() { std::cout << "printer \n"; }
    void run() override { /* do something */ };
};

class Scanner : public Machine
{
public:
    Scanner() : Machine() { std::cout << "scanner \n"; }
    void run() override { /* do something */ };
};

class PrinterScanner : public Printer, public Scanner
{
public:
    PrinterScanner() : Printer(), Scanner() { std::cout << "printer & scanner \n"; }
};

int main()
{
    PrinterScanner ps;
    ps.run(); // 无法通过编译
}

通过 ps 对象调用 run() 函数的时候,编译器无法得知我们究竟想调用的是来自 Printer 的 run() 函数还是来自 Scanner 的 run() 函数。当然我们还是可以通过显示调用 run() 函数来告知编译器我们的行为。

PrinterScanner ps;
ps.::Printer::run();
ps.::Scanner::run();

不如换种做法?

无论是多重继承抑或虚拟继承,它们自身都有缺陷,在这种情况下组合是不是比继承更加合适?

class Material { /* ... */ };

class Machine
{
public:
    ~Machine() {}
    virtual void run(Material material) = 0;
};

class Printer : public Machine
{
public:
    Printer() : Machine() {}
    void run(Material material) override { /* print material */ };
};

class Scanner : public Machine
{
public:
    Scanner() : Machine() {}
    void run(Material material) override { /* scan material */ };
};

class PrinterScanner
{
public:
    void printMaterial(Material material) { printer.run(material); }
    void scanMaterial(Material material) { scanner.run(material); }

private:
    Printer printer;
    Scanner scanner;
};

总结

大多数情况下,我们往往是不需要多重继承的,因为它并不存在着明显的优势。而且还会为程序和代码的设计带来很多负面效果。除非只有多重继承才能解决问题的时候才用多重继承,其余情况一律避免使用。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值