part 1. 虛函式
關於c++繼承,我們先來看一小段**。base表示基類,derived表示base的繼承類。
#include
using namespace std;
class base;
~base() ;
void print()
protected://protected許可權,繼承類可訪問
int base_a, base_b;
};class derived : public base;
~derived() ;
void print()
private:
int derived_c;
};int main()
執行結果為,
注意到,
base *p = new derived(1,2,3);//基類指標指向繼承類
p->print();//呼叫基類函式
delete p;//只釋放基類資源,未釋放繼承類資源
即便基類指標指向的是繼承類的物件,但實際呼叫的是仍然是基類的成員函式和析構函式,特別地,在析構函式呼叫時,繼承類析構函式未被呼叫,這樣易造成記憶體洩漏!這是因為,當基類指標被用來指向繼承類物件時,會進行指標型別轉換,將繼承類物件的指標先轉換為基類的指標,所以基類指標指向的是繼承類物件中的基類部分,這種方法是無法通過基類指標去呼叫派生類物件中的成員函式的。
解決方法是,通過使用虛函式:當把基類的某個成員函式宣告為虛函式後,允許在其繼承類中對該函式進行重新定義,賦予它新的功能,並且可以通過指向基類的指標指向不同的繼承類,從而呼叫其中的同名函式。這樣看來,虛函式可以實現動態呼叫的效果。
由此,我們調整**,
virtual ~base() ;
virtual
void print()
執行結果為,
可以看出,當基類指標指向繼承類的物件時,如果使用虛函式,可以使得呼叫的函式為繼承類中重新定義的方法。當基類有多個繼承類時,可以通過這種方法方便地實現不同繼承類方法的動態繫結!
part 2. 純虛函式
純虛函式沒有實現體,基本形式為, virtual void function_name()=0; 如,
class figure;
此時,figure類就變成了抽象類,抽象類不能例項化乙個物件,但可以有指標,具體的實現由其繼承類來實現。當基類方法不好確定或將來的行為多種多樣時,而此行為又是必須的,就可以在基類的設計中,引入虛函式的概念。
這裡列舉乙個完整的例子,
#include
#include
using
namespace
std;
class point
void print() const
};class figure//基類
//注意:這裡函式是返回引用,而不是副本(非引用);但如果返回值是函式內部變數時,則無法使用返回引用,否則當函式呼叫完成時,臨時變數也會被撤銷,程式報錯。
point& location()
void move(point p)
//虛函式
virtual
void draw() = 0;
virtual
void rotate(double) = 0;
};class circle : public figure//figure 的繼承類
void draw()
void rotate(double)
};class square : public figure//figure的另乙個繼承類
void draw()
void rotate(double a)
void vertices()
};int main()
執行結果為,
基類figure類中的虛函式draw()和rotate(double)方法沒有方法體,具體的實現是在繼承類square類和circle類中實現的。
虛函式 虛繼承 C
關於虛表,我們就要用到乙個關鍵字 virtual,可以修飾函式,也可以修飾類。類的成員函式被virtual修飾之後,就成為了虛函式 修飾類,主要是虛繼承。在此之前,我們首先要了解乙個概念 物件模型,也就是說,乙個基類形成之後,裡面的成員是怎麼存放的,當派生類繼承基類之後,派生類的成員是怎麼存放的。我...
c 虛函式和虛繼承
c 中,多型的實現需要虛函式,而虛函式主要包括兩部分,虛函式指標和虛函式表。基類將自己的一些函式設為虛函式,子類則需要在繼承基類後,重寫或者直接使用從基類的繼承下來的虛函式。基類自己會儲存乙份虛函式表,這個虛函式表含有指向基類虛函式的虛函式指標。當子類繼承基類後,同樣會將基類的虛函式表繼承下來,這樣...
虛函式 虛繼承
include using namespace std class a class b public a class c public b int main 結果是 4,4,4 為什麼?一,在private,protect,public的實際繼承中,派生類和基類擁有相同的虛函式表。但如果是虛繼承,會...