静态类型(在编译时可知的引用类型或指针类型)
动态类型(指针或引用所绑定的对象的类型这是仅在运行时可知的)
- #include <iostream>
- using namespace std;
- class A
- {
- public:
- A()
- {
- fun();
- };
- //private: //如果这里设置为private则编译不通过
- virtual void fun(int i=10)
- {
- cout<<"A init; "<<i<<endl;;
- }
- };
- class B:public A
- {
- public:
- B(){
- cout<<"B init2"<<endl;
- };
- virtual void fun2()
- {
- cout<<"B fun2 "<<endl;
- }
- virtual void fun(int i=88)
- {
- cout<<"B init "<<i<<endl;
- }
- };
- int main()
- {
- B b;
- A* p=&b;
- p->fun();
- system("pause");
- return 0;
- }
为什么编译不通过?
(当设置为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