C++虚函数工作原理:声明虚函数的类中会有一个隐藏变量(所以会多4个字节),主要指向虚函数地址的表。如果子类没有重写父类的虚函数,子类中的虚函数地址表中该虚函数地址跟父类一样,如果重写了父类的虚函数,则该虚函数地址则为新的。如果一个函数没有申明为虚函数,编译器会进行静态联编,如果改行申明为虚函数,编译器则进行动态联编。所以在程序运行时,发现调用的函数是虚函数时,会在对象的虚函数表中查找该函数的地址。
看以下例子:
#include<iostream> using namespace std; class A { public: void Print(){cout<<"A"<<endl;} }; class B:public A { public: void Print(){cout<<"B"<<endl;} }; class C { public: virtual void Print(){cout<<"C"<<endl;} }; class D:public C { public: void Print(){cout<<"D"<<endl;} }; int main() { B b; D d; A &a = b; a.Print(); //输出是A,静态联编 C &c = d; c.Print(); //输出是D,动态联编,通过虚函数表查找函数地址 return 0; }
一个函数的析构函数最好申明为虚函数,不然很有可能导致资源泄露
#include<iostream> #include<cstdio> using namespace std; class A { public: A(){cout<<"A"<<endl;} ~A(){cout<<"~A"<<endl;} }; class B:public A { public: B(){cout<<"B"<<endl;} ~B(){cout<<"~B"<<endl;} }; class C { public: C(){cout<<"C"<<endl;} virtual ~C(){cout<<"~C"<<endl;} }; class D:public C { public: D(){cout<<"D"<<endl;} ~D(){cout<<"~D"<<endl;} }; int main() { A *a = new B(); delete a; /*没有调用B的析构 A B ~A */ C *c = new D(); delete c; /* A B ~B ~A */ return 0; }
C++ 子类写父类的函数叫重写,即使参数不一样或者名字不一样,都叫重写。父类如果有3个函数,void fun(),void fun(int) ,void fun(int,int);子类即使重写了void fun()这一个函数,父类的void fun(int),void fun(int,in)在子类中也被隐藏,所以每次子类重写父类函数时,需要把父类所有重载的函数都要写一遍。