多重继承
- 多重继承有何不妥?
- 继承也可以虚拟化?
- 虚拟继承也有自己的问题
- 不如换种做法?
- 总结
多重继承有何不妥?
多重继承指的是某个类同时继承了两个或以上的其他类。那么多重继承存在着什么问题呢?
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
同时继承了 Printer
和 Scanner
。而 Printer
和 Scanner
又同时单一继承了 Machine
,自然就会构造出两个 Machine
子对象。虽然问题不大,但重复的子对象略显多余,有没有办法可以让最 Printer
和 Scanner
"共享"一个 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;
};
总结
大多数情况下,我们往往是不需要多重继承的,因为它并不存在着明显的优势。而且还会为程序和代码的设计带来很多负面效果。除非只有多重继承才能解决问题的时候才用多重继承,其余情况一律避免使用。