首先介绍一个原则LSP(Liskov Substitution Principle),如果Class D以Public方式继承Class B,则所有B对象可以派上用场的任何地方,D对象一样可以派上用场。
对于重载和重写,相信大家都已经有所了解。这里讨论一下在public继承的时候,重载函数的问题。
先看下面的例子:
1 class Base 2 { 3 public: 4 virtual void mf1() = 0; 5 virtual void mf1(int); 6 virtual void mf2(); 7 void mf3(); 8 void mf3(double); 9 ... 10 private: 11 int x_; 12 }; 13 class Derived:public Base 14 { 15 public: 16 virtual void mf1(); 17 void mf3(); 18 void mf4(); 19 ... 20 };
在基类中,mf1() 和mf3()都被重载,子类public继承父类,这里的子类覆盖了父类中所有名为mf1和mf3的函数。因而以下调用有些会失败。
Derived d; int x; ... d.mf1(); // Derived::mf1 d.mf1(x); //错误 Derived::mf1 hiden Base::mf1 d.mf2(); // Base::mf2 d.mf3(); // Derived::mf3 d.mf3(x); //错误Derived::mf3 hiden Base::mf3
由此可见,及时子类和父类内的函数有不同的参数时,子类的函数还是会覆盖所有父类中同名的函数。
这样做的原因:避免从疏远的父类中继承重载函数。但是实际上,public继承应该遵循LSP原则,即父类和子类是Is-a 的关系,所以我们可以通过using,显示地实现对父类同名重载函数的继承。
1 class Base{...}; //同上 2 class Derived:public Base{ 3 public: 4 //让Base class内名为mf1与mf3的所有东西在 5 //Derived作用域内都可见(并且都是public) 6 using Base::mf1; 7 using Base::mf3; 8 ....//同上 9 };
Derived d; int x; ... d.mf1(); //no problem. call Derived::mf1 d.mf1(x); //no problem. Base::mf1 d.mf2(); //no problem. call Base::mf2 d.mf3(); //no problem. call Derived::mf3 d.mf3(x); //no problem. Base::mf3
如果你不想继承所有的重载函数,则你不应该使用public继承,因为这样会违反LSP原则,你可以使用private继承,为了选择性的继承重载函数,可以使用inline 转交函数(forwarding function),具体实现如下:
1 class Base 2 { 3 public: 4 virtual void mf1() = 0; 5 virtual void mf1(int); 6 ... //same as above 7 }; 8 class Derived:private Base 9 { 10 public: 11 virtual void mf1()//转交函数(forwarding function) 12 { 13 Base::mf1(); 14 } 15 ... 16 }; 17 ... 18 Derived d; 19 int x; 20 d.mf1(); //good! call Derived::mf1 21 d.mf1(x); //Error as suppose,Base::mf1() was hidden.
关键:
子类内的名称会遮掩父类内的名称,在pubilc继承下,不应该这样做。
为了使被遮掩的名称可见,使用using声明或者转交函数。
时间: 2024-09-15 14:15:11