绝不重新定义继承而来的non-virtual函数
时间:2023-05-07 19:07:01
假设我告诉你,class D是由class B以public形式衍生而来,class B定义有一个public成员函数mf。由于mf参数和返回值并不重要,所以我认为它们是void。看下面的代码:
// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" class B { public: void mf(); }; class D : public B { //public: // void mf(); }; int main() { D x; B* pB = &x; pB->mf(); D* pD = &x; pD->mf(); return 0; }
在这段代码中,pB和pD调用的mf都在基类里mf()。无论他们的指针是指基类对象还是衍生对象。
看下面的代码:
// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" class B { public: void mf(); }; class D : public B { public: void mf(); }; int main() { D x; B* pB = &x; pB->mf(); D* pD = &x; pD->mf(); return 0; }
现在pD和pB调用是各自的mf了。造成这种行为的是,non-virtual函数如B::mf和D::mf都是静态绑定。这句话的意思是,因为pB声明是一个pointer-to-B,通过pB调用的non-virtual即使函数总是B定义的版本,pB指向一种类型B类派生的class”对象。
但另一方面,virtual函数是动态绑定的,所以没有这个问题。mf是一个virtual无论是通过函数pB还是pD调用mf。会导致调用D::mf,因为pB和pD真正指向的是D类型的对象。
假如你在写class D并重新定义继承自class B的non-virtual函数mf,D对象很可能表现出精神分裂症的不一致行为。更清楚地说,当mf任何D对象都可能显示B或BD的行为。决定因素不是对象本身,而是对象本身 指向对象的指针类型。References与指针一样难以理解。
这就解释了为什么基类分析函数应该设计为virtual函数!