1 虚函数
虚函数( 基类指针可指向派生类对象, 动态联编)
先看示例,不加virtual,不认对象认指针。
#include <iostream>using namespace std;class A{
public:A(){ }~A(){ }void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:void show(){cout<<"BBBBBBBBBBBBB"<<endl;}};int main()
{/*A a;a.show();//AAAAAAAAAAAAAAX b;b.show();//BBBBBBBBBBBBB
*/AX a;//定义派生类AX *q = &a; //认函数A *p = &a;q->show(); //BBBBBBBBBBBBBp->show(); //AAAAAAAAAAAAA}
加上virtul,通过指针找到对象,对象类型是什么调什么函数。动态链接的方式。
#include <iostream>using namespace std;class A{
public:A(){ }~A(){ }virtual void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:void show(){cout<<"BBBBBBBBBBBBB"<<endl;}};int main()
{/*A a;a.show();//AAAAAAAAAAAAAAX b;b.show();//BBBBBBBBBBBBB
*/AX a;//定义派生类AX *q = &a; //认函数A *p = &a;q->show(); //BBBBBBBBBBBBBp->show(); //BBBBBBBBBBBBB}
2 多态应用
设计一个函数能求多个“图形”总周长。
纯虚类用法
#include <iostream>using namespace std;class shape{
public:virtual double getC(void) = 0; //纯虚函数的声明,表示在派生类中必须实现该函数,否则编译器不通过。
// { //虚函数可以不要求派生类必须实现// }
};class Cir:public shape{
public:Cir(double ri):r(ri) { }double getC(void){return 2*3.14*r; }
private:int r;
};class Tri:public shape{
public:Tri(double a, double b, double c):e1(a),e2(b),e3(c){ }double getC(void){return e1+e2+e3; }
private:double e1;double e2;double e3;
};class Rec: public shape{
public:Rec(double e){this->e = e;}double getC(void){return 4*e; }private:double e;
};double countC(shape *arr[], int n)
{double sum = 0;for(int i=0; i<n; i++){sum += arr[i]->getC();}return sum;
}int main()
{//shape x; //如果是纯虚函数的声明会编译不通过Cir c(1);Rec r(3);Cir c1(2);Tri t(3,3,3);shape *arr[] = {&c, &r, &c1, &t};cout << "total C: "<<countC(arr, 4) << endl;
}
3 虚析构函数
现象
#include <iostream>using namespace std;class A{
public:A(){ }~A(){ cout<<"A~~~~~~~~~"<<endl; }//virtual ~A(){ cout<<"A~~~~~~~~~"<<endl; } //加virtual 也一样调用3次virtual void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:~AX(){ cout<<"AX~~~~~~~~~"<<endl; }void show(){cout<<"BBBBBBBBBBBBBB"<<endl;}};int main()
{AX a; //派生类构造的时候调用了1次基类构造函数,所以析构的时候有2次A b;
}//析构函数调用了3次A~~~~~~~~~ //a
AX~~~~~~~~~ //a
A~~~~~~~~~ //b
#include <iostream>using namespace std;class A{
public:A(){ } virtual ~A(){ cout<<"A~~~~~~~~~"<<endl; } //加virtual 也一样调用3次virtual void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:~AX(){ cout<<"AX~~~~~~~~~"<<endl; }void show(){cout<<"BBBBBBBBBBBBBB"<<endl;}};int main()
{AX a; //派生类构造的时候调用了1次基类构造函数,所以析构的时候有2次A b;
}//析构函数调用了3次A~~~~~~~~~ //a
AX~~~~~~~~~ //a
A~~~~~~~~~ //b
#include <iostream>using namespace std;class A{
public:A(){ }virtual ~A(){ cout<<"A~~~~~~~~~"<<endl; }virtual void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:~AX(){ cout<<"AX~~~~~~~~~"<<endl; }void show(){cout<<"BBBBBBBBBBBBB"<<endl;}};int main()
{AX *p = new AX;delete p;
}//
AX~~~~~~~~~
A~~~~~~~~~
#include <iostream>using namespace std;class A{
public:A(){ }virtual ~A(){ cout<<"A~~~~~~~~~"<<endl; }virtual void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:~AX(){ cout<<"AX~~~~~~~~~"<<endl; }void show(){cout<<"BBBBBBBBBBBBBB"<<endl;}};int main()
{AX *p = new AX;delete p; //
}
//
AX~~~~~~~~~
A~~~~~~~~~
不安全的情况
#include <iostream>using namespace std;class A{
public:A(){ }~A(){ cout<<"A~~~~~~~~~"<<endl; }virtual void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:~AX(){ cout<<"AX~~~~~~~~~"<<endl; }void show(){cout<<"BBBBBBBBBBBBBB"<<endl;}};int main()
{A *p = new AX;delete p; //析构不完整}//
A~~~~~~~~~//virtual 用在析构函数上安全一点,防止内存泄漏
#include <iostream>using namespace std;class A{
public:A(){ }virtual ~A(){ cout<<"A~~~~~~~~~"<<endl; }virtual void show(){cout<<"AAAAAAAAAAAAA"<<endl;}};class AX:public A{
public:~AX(){ cout<<"AX~~~~~~~~~"<<endl; }void show(){cout<<"BBBBBBBBBBBBBB"<<endl;}};int main()
{A *p = new AX;delete p; }//
AX~~~~~~~~~
A~~~~~~~~~