開始學C++了,所以又重拾以前學習過的相關概念…
析構函數是當一個對象的生命周期結束時,會自動執行析構函數。
析構函數的定義:
#ifndef __A_H__
#define __A_H__
class A
{
public:
A(void);
A(int a, int b);
~A(void); //析構函數
private:
int a;
int b;
int c;
};
#endif
虛析構函數與純虛析構函數的定義(假定類名為A):
#ifndef __A_H__
#define __A_H__
class A
{
public:
A(void);
A(int a, int b);
virtual ~A(void); //虛析構函數
private:
int a;
int b;
int c;
};
#endif
#ifndef __A_H__
#define __A_H__
class A
{
public:
A(void);
A(int a, int b);
virtual ~A(void) = 0; //純虛析構函數
};
#endif
其中定義了純虛函數后,類A就成為了“抽象類”,它是不能有實例對象的。否則會報錯:
“A”: 不能實例化抽象類
由於下列成員:
“A::~A(void)”: 是抽象的
一個類維護一個虛函數相關的表--vtable(__vfptr指向它),函數聲明前面包含關鍵字“virtual”的函數,就會創建一個指向該函數的指針(函數指針)被存入vtable中。
虛函數表的作用是用來實現多態,但同時也帶來了執行效率和額外內存空間的增加。
再來看虛析構函數,它所存在的意義:基類的指針指向派生類對象,用基類的指針刪除派生類對象。
#include <iostream>
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;
}
};
int main()
{
A *a = new B();
delete a;
return 0 ;
}
輸出:
A…
B…
~A…
派生類的析構函數未被調用,為什么呢?
派生類繼承自基類,那么基類就只會存在於派生類中,直到派生類調用析構函數后。
假定:基類的析構函數調用比派生類要早,會造成的一種情況就是類成員不存在了,而類本身卻還在,但是類存在的情況下,類成員應該還存在。所以這就矛盾了,所以派生類的析構函數會先被調用,基類的析構函數再被調用。
修改一下代碼:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout <<"A..."<<endl;
}
virtual ~A()
{
cout <<"~A..."<<endl;
}
};
class B :public A
{
public :
B()
{
cout <<"B..."<<endl;
}
~B()
{
cout <<"~B..."<<endl;
}
};
int main()
{
A *a = new B();
delete a;
return 0 ;
}
輸出:
A…
B…
~B…
~A…
僅僅只是在基類的析構函數前面加了一個“virtual”,使它成為“虛析構函數”了,這就是“虛析構函數”存在的意義 :)
析構函數的作用並不是刪除對象,而是撤銷對象占用內存之前完成的一些清理工作…
//=========================================
總結:如果某個類不包含虛函數,那一般是表示它將不作為一個基類來使用。當一個類不准備作為基類使用時,就不要定義虛析構函數了,因為它會增加一個虛函數表,使得對象的體積翻倍,還有可能降低其可移值性。
所以基本的一條是:無故的聲明虛析構函數和永遠不去聲明一樣是錯誤的。
當且僅當類里包含至少一個虛函數的時候,才去聲明虛析構函數。
抽象類是准備被用做基類的,基類必須要有一個虛析構函數,純虛函數會產生抽象類,所以在想要成為抽象類的類里聲明一個純虛析構函數。
定義一個函數為虛函數,不代表該函數未被實現,只是為了來實現多態。
定義一個函數為純虛函數,才表示函數未被實現 ,定義它是為了實現一個接口,起一個規范作用。繼承抽象類的派生類要實現這個函數…
看下面的代碼,如何輸出:
//A.h
#ifndef __A_H__
#define __A_H__
class A
{
public:
A(void);
A(int a, int b);
virtual ~A(void);
virtual void numAdd() = 0;
virtual void f();
void ff();
private:
int a;
int b;
int c;
};
#endif
//A.cpp
#include "A.h"
#include <iostream>
using namespace std;
A::A(void)
{
}
A::A(int a, int b)
{
this->a = a;
this->b = b;
cout<<"a:"<<a<<" b:"<<b<<endl;
}
A::~A(void)
{
cout<<"~A"<<endl;
}
void A::f()
{
cout<<"A::f()"<<endl;
}
void A::ff()
{
cout<<"A::ff()"<<endl;
}
//B.h
#ifndef __B_H__
#define __B_H__
#include "a.h"
class B :public A
{
public:
B(void);
~B(void);
virtual void numAdd();
void f();
virtual void ff();
};
#endif
//B.cpp
#include "B.h"
#include <iostream>
using namespace std;
B::B(void)
{
}
B::~B(void)
{
cout<<"~B"<<endl;
}
void B::numAdd()
{
}
void B::f()
{
cout<<"B::f()"<<endl;
}
void B::ff()
{
cout<<"B:ff()"<<endl;
}
main函數的定義:
//main()
B b;
A * a = &b;
a->f();
a->ff();
return 0;
輸出什么?
…
B::f()
A::ff()
//定義指向基類對象的指針a,當調用f()方法時,因為f為虛函數,所以調用了派生類的f(),輸出B::f();
參考: