Welcome

首页 / 软件开发 / C++ / 避免对派生的非虚函数进行重定义

避免对派生的非虚函数进行重定义2013-05-27 51cto 驿落黄昏今天无意中发现一个关于C++基础的问题,当时愣是没理解是什么原因,现在搞明白了,就写下来了 。先看小程序,先实践再理论吧,要不大家就睡着了。

#include <iostream>using namespace std;class Base{public:virtual void funtion(int arg = 1){cout<<arg<<endl;} };class Derive : public Base{public:virtual void funtion(){cout<<"Derive"<<endl;}virtual void funtion(int arg){cout<<"Derive"<<arg<<endl;}};int main(int argc, char *argv[]){Base* obj = new Derive();obj->funtion();system("pause");return 0;}
上面的程序会出现什么结果呢?我想会有很多人看到这个地方就会怀疑我程序的正确性了, 大呼“你的程序是错的”,但真的错吗?我们可以先执行下程序看下结果。很明显,结果是调用了子类 的函数,并且子类中arg参数的值是父类中的值1,运行结果为“Derive 1”。

下面我就解释下 这种结果的原因,首先我先要说下对象的两种类型:动态类型和静态类型。

静态类型:指针或 者是引用声明时的类型。

动态类型:由他实际指向的类型确定。

例如:

Base *pgo= //pgo静态类型是Base *new Derive; //动态类型是Derive *Asterioid *pa = new Asterioid; //pa的静态类型是 Asterioid *//动态类型也是 Asterioid *pgo = pa; //pgo静态类型总指向Base *//动态类型指向了 Asterioid *Base &rgo = *pa; //rgo的静态类型是Base//动态类型是 Asterioid
虚函数是动态绑定的,而默认参数值是静态绑定的。运行时效率。 如果默认参数值是动态绑定的话,那么编译器必须提供一整套方案,为运行时的虚函数参数确定恰当的 默认值。而这样做,比起C++当前使用的编译时决定机制而言,将会更复杂、更慢。鱼和熊掌不可兼得 ,C++将设计的中心倾向了速度和简洁,你在享受效率的快感的同时,如果你忽略本条目的建议,你就 会陷入困惑。

其实对于这个问题在[Effective C++第3版]中也有提到,其第36条:避免对派生 的非虚函数进行重定义。下面看下书中的描述:

现在考虑以下的层次结构:B是一个基类,D是 由B的公有继承类,B类中定义了一个公有成员函数mf,由于这里mf的参数和返回值不是讨论的重点,因 此假设mf是无参数无返回值的函数。也就是说:

class B {public:void mf();};class D: public B {};即使不知道B、D、mf的任何信息,让我们声明一个D的对象x:D x; // x 是D类型的对象B *pB = &x; // 指向x的指针pB->mf(); // 通过指针调用mf函数D *pD = &x; // 指向x的指针pD->mf(); // 通过指针调用mf函数