今天无意中发现一个关于C++基础的问题,当时愣是没理解是什么原因,现在搞明白了,就写下来了。先看小程序,先实践再理论吧,要不大家就睡着了。
|
上面的程序会出现什么结果呢?我想会有很多人看到这个地方就会怀疑我程序的正确性了,大呼“你的程序是错的”,但真的错吗?我们可以先执行下程序看下结果。很明显,结果是调用了子类的函数,并且子类中arg参数的值是父类中的值1,运行结果为“Derive 1”。
下面我就解释下这种结果的原因,首先我先要说下对象的两种类型:动态类型和静态类型。
静态类型:指针或者是引用声明时的类型。
动态类型:由他实际指向的类型确定。
例如:
|
虚函数是动态绑定的,而默认参数值是静态绑定的。运行时效率。如果默认参数值是动态绑定的话,那么编译器必须提供一整套方案,为运行时的虚函数参数确定恰当的默认值。而这样做,比起C++当前使用的编译时决定机制而言,将会更复杂、更慢。鱼和熊掌不可兼得,C++将设计的中心倾向了速度和简洁,你在享受效率的快感的同时,如果你忽略本条目的建议,你就会陷入困惑。
其实对于这个问题在[Effective C++第3版]中也有提到,其第36条:避免对派生的非虚函数进行重定义。下面看下书中的描述:
现在考虑以下的层次结构:B是一个基类,D是由B的公有继承类,B类中定义了一个公有成员函数mf,由于这里mf的参数和返回值不是讨论的重点,因此假设mf是无参数无返回值的函数。也就是说:
|
在这里,如果告诉你pD->mf()与pB->mf()可能拥有不同的行为,你一定会感到意外。这也难怪:因为两次都是在调用x对象的成员函数mf,因为两种情况下都是用了同一函数和同一对象,mf()理所应当应该有一致的行为。难道不是吗?