静态类型(在编译时可知的引用类型或指针类型)

动态类型(指针或引用所绑定的对象的类型这是仅在运行时可知的)

  1. #include <iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5. public:  
  6.     A()  
  7.     {  
  8.         fun();  
  9.     };  
  10.   
  11. //private: //如果这里设置为private则编译不通过  
  12.     virtual void fun(int i=10)   
  13.     {  
  14.         cout<<"A init; "<<i<<endl;;  
  15.     }  
  16. };  
  17. class B:public A  
  18. {  
  19. public:  
  20.     B(){  
  21.         cout<<"B init2"<<endl;  
  22.     };  
  23.       
  24.     virtual void fun2()  
  25.     {  
  26.         cout<<"B fun2 "<<endl;  
  27.     }  
  28.     virtual  void fun(int i=88)  
  29.     {  
  30.         cout<<"B init "<<i<<endl;  
  31.     }  
  32. };  
  33. int main()  
  34. {  
  35.     B b;  
  36.     A* p=&b;  
  37.     p->fun();  
  38.     system("pause");  
  39.     return 0;  
  40. }  


 


为什么编译不通过?

(当设置为public 时,输出: B init 10 )

过程:

1,在编译阶段,p->fun(); 只是按其静态类型来处理的, 在这里为类型A。

也就是说,碰到p->fun(); 编译器就当作调用A的fun来进行相应的检查和处理。

例如 A类中 fun()设为private的时,类用户是不能访问的,所以编译出错。

2,运行时,

B b; 这条语句执行了以下操作:(PS:类的非静态成员函数都会编译加一个指针参数,指向调用该函数的对象,我们平常用的this就是该指针的值)

(1)调用基类的构造函数,通过附加的this指针(指向的是b),把b对应的虚函数表中的第一项改为:A::fun(int)

(2)调用派生类的构造函数,能过附加的this指针(指向b),把b对应的函数表中的第一项改为:B:fun(int),把刚才的覆盖了。

PS:虚函数表里的每一项 都保存 着函数指针 ,最后是一项是一个结束标记。

所以执行p->fun();的时候,实际上执行的B::fun()。

 

 为什么输出 10

C++的注意条款中有一条" 绝不重新定义继承而来的缺省参数值" (Effective C++ Item37, never redefine a function's inherited default parameter value) 也是同样的道理。

如果通过基类的引用或指针调用虚函数,但实际执行的是派生类中定义的版本,这时就可能会出现问题。

在这种情况下,为虚函数的基类版本定义的默认实参将传给派生类定义的版本,而派生类版本是用不同的默认实参定义的。

 

更多解析请看http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html

posted on 2013-03-04 17:13  侠骨豪情  阅读(254)  评论(0编辑  收藏  举报