300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 避免在派生类中重新定义基类的非虚函数

避免在派生类中重新定义基类的非虚函数

时间:2020-07-31 22:12:29

相关推荐

避免在派生类中重新定义基类的非虚函数

我们都知道,在基类中定义虚函数的目的是允许派生类拥有相同接口却可以有不同的实现,通过对象的指针或引用来访问虚函数可以实现运行时的多态。这么说来,在派生类中重定义(override)虚函数是没有任何问题的。那么,可以重定义基类中的非虚函数吗?

答案是:技术上你可以这样做(至少编译器不会报错),但是绝大多数情况下不应该做。

class Base{public:void f() {cout << "Base::f()" << endl; }};class Derived: public Base{public:void f() {cout << "Derived::f()" << endl; }};int main(){Derived d;Base *pb = &d;// Base::f()pb->f();Derived *pd = &d;// Derived::f()pd->f(); }

上面的代码有一个诡异的行为:对同一个派生类对象调用同样的函数,返回的结果是不一样的。这是因为普通的非虚函数体在编译期就与函数调用绑定,指针的类型决定了哪个函数被调用。通过Base调用的f一定是基类的,而通过Derived调用的f一定是派生类的。

从面向对象的角度来说,在派生类中重定义基类中的非虚函数可能会违反公有继承Is-A的关系。公有继承是说每一个派生类对象都可以被当做基类对象来处理。基类的每一个接口和不变量派生类也有。而非虚函数的具体实现是类不变量的一部分。如果重定义了非虚函数,类不变量就可能被打破,派生类对象将不再是基类对象(当通过指向派生类对象的指针访问f时)。

很少情况下,需要重定义非虚函数。一个特例是为了解决私有继承中的名字隐藏问题。在私有继承中,基类的公有函数在派生类中都是私有,如果派生类想要继承基类的某个接口,可以使用所谓的forwarding function。即通过定义一个与基类一模一样的函数,它的实现仅仅是调用基类的对应函数。注意,使用using语句是不可行的,它会把同名的所有重载函数(f()与f(int))都一起导入派生类,参见:C++名字隐藏对公有继承的影响

class Base{public:f();f(int i);};class Derived: private Base{public:// forwarding functionf() {Base::f(); }};

小结:

绝大多数情况下不要重新定义基类的非虚函数,那样会打破公有继承Is-A的关系,而且行为诡异。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。