要触发动态绑定必须满足两个条件:
1.只有指定为虚函数的成员函数才能进行动态绑定
2.必须通过基类类型的引用或者指针进行函数调用
-----摘自《C++ Primer》
对于第二点,我开始产生这样的疑问:
Q1:为什么只能是引用或指针,直接对象调用不可以吗?
Q2:为什么只能通过基类的引用或指针,而不能派生类的指针或引用?
A1:通过对象来调用,当赋值时候派生类对象赋值给基类时候,它们发生了类型转换了,当然不能动态绑定了;
而通过指针和引用却可以,为什么,因为出现虚函数,编译器就为这个基类提供一张虚函数表,保存着派生类的地址,因此通过基类指针或引用操作可以实现动态绑定。
A2:这个更简单,假如基类能赋值给派生类,那当派生类指针调用它有的当基类没有的函数怎么办?所以编译器禁止这样赋值(我理解这种转换为类型的向上转换,
向下转换可以通过,向下又称截断转换),所以用它来动态绑定。
下面是我的测试
class A{ public: A(){} virtual ~A(){} void dispaly() { std::cout<<"TEST A"<<std::endl; } virtual void dispalyEx() { std::cout<<"this is A called"<<std::endl; } }; class B:public A{ public: B(){} ~B(){} void dispaly() { std::cout<<"TEST A"<<std::endl; } void dispalyEx() { std::cout<<"this is B called"<<std::endl; } void test() { std::cout<<"Test B~!"<<endl; } };
对于上面两个类,这样调用时候能发生动态绑定:
A *pa,a;
B *pb,b;
pa->dispalyEx(); //结果: this is A called
pa = &b;
pa->dispalyEx(); //结果:this is B called
//而这样不能发生动态绑定:
a.dispalyEx(); //结果: this is A called
a=b;//截断转换 可以通过
a.dispalyEx(); //结果: this is A called 不能动态绑定
b = a;//编译出错 向上转换 编译器的错误信息提示 没有找到接受“A”类型的右操作数的运算符(或没有可接受的转换)
pb = pa;同上