虚函数总结:
虚函数只能是类成员函数,它在基类体内部说明,目的是提供一种接口界面;
虚函数不能是友元函数(即非成员函数),也不能是静态成员函数,因为虚函数调用要靠特定的对象来决定该激活哪个函数。虚函数可以在另一个类中被声明为友元函数;
一旦一个函数定义为虚函数,那么无论它传下多少层,都将保持为虚函数,而不必每次都加关键字virtual;
基类的虚函数可在一个或多个派生类中被重新定义,但其原型与基类必须完全相同(即返回类型、函数名、参数个数、类型及顺序一样),否则系统将认为派生类中的函数是重载的,而非虚函数;如果仅有返回类型不同,那么编译将出错;
要虚函数发挥作用,必须用基类的指针(或引用)指向派生类的对象,并用指针(或引用)调用虚函数。也就是说,只有用地址才能体现运行多态性。因为不论是指向基类还是指向派生类的指针(引用),大小都是一样的,这样才能用基类指针指向派生类对象。这时,指针提供的信息是不完全的,在编译阶段不知道应该调用虚函数的哪个版本。而如果用对象调用虚函数,由于类型已经确定了,因此编译系统很可能采用预绑定;
由于包含虚函数的基类指针可以指向其不同的派生类,并可执行不同版本的虚函数,提供了实现程序运行的多态性方法,因而将包含虚函数的类称为多态类。
虚函数与一般重载函数的区别:
重载函数在类型和参数数量上一定不相同,而重定义的虚函数则要求参数的类型和个数、函数返回类型相同;
虚函数必须是类的成员函数,重载的函数则不一定是这样;
构造函数可以重载,但不能是虚函数,析构函数可以是虚函数。
虚函数必须是类的成员函数,重载的函数则不一定是这样;
构造函数可以重载,但不能是虚函数,析构函数可以是虚函数。
指针的转换规则:
指向基类的指针,可以指向它的公有派生的对象,但不能指向私有派生的对象;
只能利用它直接访问派生类从基类继承来的成员,不能直接访问公有派生类中特定的成员;
不能将指向派生类对象的指针指向其基类的一个对象。
只能利用它直接访问派生类从基类继承来的成员,不能直接访问公有派生类中特定的成员;
不能将指向派生类对象的指针指向其基类的一个对象。
当虚函数在操作中引用的基类数据成员无法被派生类直接引用时(例如被隐藏的成员),便会出现错误。为了使用虚函数达到最好的动态联编效果,一般应以该虚函数第一次出现的类的引用体或指针作为参数,避免不确定因素。
#include < IOSTREAM.H > // 基类 class CBase { int x; public: CBase(int n) {x=n;} virtual void PrintX() {cout<<"CBase::PrintX : "<<x<<endl;} } ; // 派生类 class CDerive : public CBase { int x; public: CDerive(int n1,int n2):CBase(n1) { x=n2; } void PrintX() { cout<<"CDerive::PrintX : "<<x<<endl; CBase::PrintX(); } } ; // 子派生类 class CSubDerive : public CDerive { int x; public: CSubDerive(int n1,int n2,int n3):CDerive(n1,n2) { x=n3; } void PrintX() { cout<<"CSubDerive::PrintX : "<<x<<endl; CDerive::PrintX(); } } ; void main() { cout<<"CBase size = "<<sizeof(CBase)<<endl; cout<<"CDerive size = "<<sizeof(CDerive)<<endl; cout<<"CSubDerive size = "<<sizeof(CSubDerive)<<endl; cout<<endl; CBase obj1(1); CDerive obj2(2,3); CSubDerive obj3(4,5,6); obj1.PrintX(); obj2.PrintX(); obj3.PrintX(); cout<<endl; CBase *pObj1=&obj1; CDerive *pObj2=&obj2; CSubDerive *pObj3=&obj3; pObj1->PrintX(); pObj2->PrintX(); pObj3->PrintX(); cout<<endl; CBase *pObj[]={pObj1,pObj2,pObj3};//用指针的方法 pObj[]->PrintX(); pObj[1]->PrintX(); pObj[2]->PrintX(); cout<<endl; CBase &yobj1=obj1;//用引用的方法 CBase &yobj2=obj2; CBase &yobj3=obj3; yobj1.PrintX(); yobj2.PrintX(); yobj3.PrintX(); }