抽象類是為了抽象和設計的目的而建立的,處於繼承層次結構的上層。定義了純虛函式的類就是抽象類。
具體類是能夠建立物件的類。
抽象類的規定
(1)抽象類只能用作其他類的基類,不能建立抽象類物件。
(2)抽象類不能用作引數型別、函式返回型別或顯式轉換的型別。
(3)可以定義指向抽象類的指標和引用,此指標可以指向它的派生類,進而實現多型性。
#includeusing namespace std;
const double pi=3.14159;
class shapes //抽象類
; // 定義了純虛函式,就需要定義純虛析構函式
void setvalue(int d, int w=0)
virtual void disp()=0;// 純虛函式
};
class square:public shapes
輸出:矩形面積:50
圓面積:314.159
這個類有乙個純虛函式,所以它是抽象的。
如果只定義乙個虛析構函式原型,而不給出函式體:
virtual ~shapes();
會報鏈結錯誤。
所以必須提供虛析構函式的定義:
1
shapes::~shapes()
// 純虛析構函式的定義
這個定義是必需的,因為虛析構函式工作的方式是:最底層的派生類的析構函式最先被呼叫,然後各個基類的析構函式被呼叫。這就是說,即使是抽象類,編譯器也要產生對~shapes的呼叫,所以要保證為它提供函式體。
如果不定義虛析構函式,即把
virtual ~shapes(){};
這一行注釋掉,鏈結器就會檢測出來,報警告:
./virtual_fun.cpp:7: warning: 'class shapes' has virtual functions but non-virtual destructor
./virtual_fun.cpp:17: warning: 'class square' has virtual functions but non-virtual destructor
./virtual_fun.cpp:24: warning: 'class circle' has virtual functions but non-virtual destructor
如果給出了虛析構函式的宣告,但不定義,即不提供函式體(去掉兩個花括號),那麼報如下錯誤:
/tmp/ccmjpeta.o: in function `shapes':
./virtual_fun.cpp:7: undefined reference to `vtable for shapes'
/tmp/ccmjpeta.o: in function `~square':
./virtual_fun.cpp:17: undefined reference to `shapes::~shapes()'
/tmp/ccmjpeta.o: in function `~circle':
./virtual_fun.cpp:24: undefined reference to `shapes::~shapes()'
./virtual_fun.cpp:24: undefined reference to `shapes::~shapes()'
/tmp/ccmjpeta.o: in function `~square':
./virtual_fun.cpp:17: undefined reference to `shapes::~shapes()'
/tmp/ccmjpeta.o:(.rodata._zti6square[typeinfo for square]+0x8): undefined reference to `typeinfo for shapes'
/tmp/ccmjpeta.o:(.rodata._zti6circle[typeinfo for circle]+0x8): undefined reference to `typeinfo for shapes'
collect2: ld returned 1 exit status
下面以rpg遊戲中4個類為例來介紹:
玩家類,劍士類、弓箭手類、魔法師類
。 其中玩家類作為父類,劍士類、弓箭手類、魔法師類分別繼承玩家類,作為子類。當我們開始遊戲時,需要選擇建立某乙個類的物件,才能進行遊戲。然而,我們的選擇不應該是4個類,而應該只能在劍士類、弓箭手類或魔法師類中做出選擇。
因為,單純的玩家類是抽象的、不完整的,任何乙個玩家必須有乙個確定的職業之後,才能確定他的具體技能。又比如學生類,它也是非常抽象的。
讓乙個小學生、中學生或本科生學習,他們都有各自學習的內容。而乙個抽象概念的學生,他卻不知道該學些什麼。
這時,我們必須要對玩家類或學生類作一些限制了。由於玩家類和學生類直接例項化而建立的物件都是抽象而沒有意義的,所以我們希望玩家類和學生類只能用於被繼承,而不能用於直接建立物件。
在c++中,我們可以把只能用於被繼承而不能直接建立物件的類設定為抽象類(abstract class)。
之所以要存在抽象類,最主要是因為它具有不確定因素。
我們把那些類中的確存在,但是在父類中無法確定具體實現的成員函式稱為純虛函式。純虛函式是一種特殊的虛函式,它只有宣告,沒有具體的定義。抽象類中至少存在乙個純虛函式;存在純虛函式的類一定是抽象類。
存在純虛函式是成為抽象類的充要條件。
那麼我們該如何定義乙個純虛函式呢?純虛函式的宣告有著特殊的語法格式:
virtual 返回值型別成員函式名(參數列)=0;
請注意,純虛函式應該只有宣告,沒有具體的定義,即使給出了純虛函式的定義也會被編譯器忽略。下面我們就修改一下程式17.7.1,將學生類變成乙個抽象類:(程式17.9)
#include
using namespace std;
class student//因為存在純虛函式study,student類自動變成了抽象類
;char * student::sname()
int student::sage()
int student::sheight()
int student::sweight()
void student::set(char *n,int a,int h,int w)
name[i]='\0';
age=a;
height=h;
weight=w;
return;
}student::student(char *n,int a,int h,int w)
student::student()
和pupil.h同程式17.7.1
#include
#include "undergraduate.h"
#include "pupil.h"
using namespace std;
int main()
執行結果:
constructing a student without parameter...
constructing a student without parameter...
學習高等數學和大學英語。
學習語數外。
我們看到,設定了純虛函式之後並不影響多型的實現,但是卻將父類變成了抽象類,限制了父類物件的建立。有了抽象類之後,就不會再出現不確定職業的玩家、不確定身份的學生了。
C 純虛函式與抽象類
純虛函式 純虛函式 在基類中將某一成員函式定為虛函式,並不是基類本身的需要,而是考慮到派生類的需 要,在基類中預留了乙個函式名,具體功能留給派生類根據需要去定義。純虛函式是在宣告虛函式時被 初始化 為0的函式。一般形式為 virtual 函式型別 函式名 引數列表 0 如 virtual float...
C 純虛函式與抽象類
在很多的情況下,在基類中一般都不能給出虛函式的具體而有意義的定義,這時我們就可以將它說明為純虛函式。它的具體的定義由它的派生類具體完成,這樣可以使類之間的結構更加清晰,同時也更容易理解。含有純虛函式的類叫抽象類。說明純虛函式的一般格式 class 類名 virtual 返回值型別 函式名 引數列表 ...
C 純虛函式與抽象類
參考 純虛函式 是一種特殊的虛函式,是基類中只有宣告,無 法實現 定義的虛函式。含有純虛函式的類稱為 抽象類 ifndef purevir h define purevir h define pi 3.14159 namespace purev 基類為 抽象類 的派生類都必須定義自己的,和純虛函式同...