黄色电影一区二区,韩国少妇自慰A片免费看,精品人妻少妇一级毛片免费蜜桃AV按摩师 ,超碰 香蕉

深入解析C++中多態(tài)性和虛函數(shù)使用原理

深入解析c++中多態(tài)性和虛函數(shù)使用原理

 

1.為什么需要virtual

按照java的思維方式,在有了繼承和向上類型轉(zhuǎn)換(upcasting)之后,就可以實(shí)現(xiàn)多態(tài)性了。但是在c++中似乎并不能orz??紤]這種情況:

#include<iostream>
using std::cout;
using std::endl;
class a{
public:
void f() const{
  cout<<"class a's function"<<endl;
}
};
class b : public a{
public:
void f() const{
  cout<<"class b's function"<<endl;
}
};
int main(){
b b;
a *ptr_a = &b;
a &ref_a = b;
ptr_a->f();//print: class a's function
ref_a.f();//print: class a's function
}

在使用基類指針或引用調(diào)用一個(gè)派生類對(duì)象的函數(shù)時(shí),我們發(fā)現(xiàn)程序仍然在調(diào)用基類的函數(shù),要想解決這種情況,就要引入virtual關(guān)鍵字,將上面代碼里的class a修改如下,main中的輸出就變成類b中f()的輸出了。

class a{
public:
virtual void f() const{
  cout<<"class a's function"<<endl;
}
};

那么為什么java不需要呢?因?yàn)関irtual關(guān)鍵字實(shí)現(xiàn)功能的同時(shí),會(huì)增加該類一些操作的時(shí)間和空間占用,c++將這部分占用的優(yōu)化決定權(quán)交給了程序員,以實(shí)現(xiàn)可能的效率提高;而java內(nèi)置了virtual的機(jī)制,沒(méi)有提高效率的選擇,但是簡(jiǎn)化了編程。(關(guān)于virtual的具體機(jī)制,建議參考thinking in c++)

有兩點(diǎn)需要注意的:

  • 第一、當(dāng)使用基類指針指向派生類時(shí),無(wú)法通過(guò)基類指針直接調(diào)用派生類中增加的函數(shù)(基類中沒(méi)有同名虛函數(shù)),除非將基類指針強(qiáng)制類型轉(zhuǎn)換為派生類指針。
  • 第二、只能通過(guò)基類指針或者引用來(lái)調(diào)用派生類對(duì)象,如果我們將一個(gè)派生類對(duì)象通過(guò)值傳遞的方式傳遞給基類對(duì)象,這個(gè)對(duì)象被真的切成一個(gè)基類對(duì)象,而不具有任何派生類的內(nèi)容。

 

2.純虛函數(shù)和抽象類

在類設(shè)計(jì)時(shí),常常希望基類僅僅作為派生類的一個(gè)接口,被繼承實(shí)現(xiàn),而不會(huì)去創(chuàng)建基類對(duì)象,這時(shí),可以在基類中定義純虛函數(shù),使其成為一個(gè)抽象類。定義純虛函數(shù)語(yǔ)法是在一個(gè)虛函數(shù)聲名的基礎(chǔ)上,加上=0。例如:virtual void f() = 0;注意:當(dāng)繼承一個(gè)抽象類時(shí),必須實(shí)現(xiàn)其所有的純虛函數(shù),否則繼承出的類也是一個(gè)抽象類。

一般情況下,在基類中我們不會(huì)對(duì)純虛函數(shù)進(jìn)行實(shí)現(xiàn),但是c++提供了實(shí)現(xiàn)純虛函數(shù)的機(jī)制,這種方法可以讓我們定義一段公共代碼,使派生類可以公用。

class a{
public:
virtual void do() = 0; 
};
/*
*純虛函數(shù)不能作為inline函數(shù)實(shí)現(xiàn),要放在類外!
*/
void a::do(){
//一些公共代碼
}
class b : public a{
public:
void do() {
  a::do();
  //其他代碼
}
};

 

3.構(gòu)造函數(shù)與虛函數(shù)

如上文所說(shuō),定義一個(gè)虛函數(shù)時(shí),需要做一些額外的工作,完成這些工作的代碼其實(shí)被秘密插入到類構(gòu)造函數(shù)的開(kāi)頭部分。那么就有一個(gè)問(wèn)題,如果我們?cè)跇?gòu)造函數(shù)中調(diào)用虛函數(shù)會(huì)發(fā)生什么現(xiàn)象?答案是,會(huì)調(diào)用這個(gè)虛函數(shù)的本地版本,即虛函數(shù)機(jī)制在構(gòu)造函數(shù)中不工作。
另外,構(gòu)造函數(shù)也不能被定義為虛函數(shù)。

 

4.虛析構(gòu)函數(shù)與純虛析構(gòu)函數(shù)

構(gòu)造函數(shù)不能被定義為虛函數(shù),而析構(gòu)函數(shù)可以,并且經(jīng)常被定義為虛函數(shù)。

#include<iostream>
using namespace std;
class base1{
public:
~base1(){cout<<"~base1()"<<endl;}
};
class base2{
public:
virtual ~base2(){cout<<"~base2()"<<endl;}
};
class derived1 : public base1{
public:
~derived1(){cout<<"~derived1()"<<endl;}
};
class derived2 : public base2{
public:
~derived2(){cout<<"~derived2()"<<endl;}
};
int main(){
base1* pd1 = new derived1();
base2* pd2 = new derived2();
delete pd1;
delete pd2;
}

上面代碼的控制臺(tái)輸出:

~base1()
~derived2()
~base2()

上面的代碼暴露出在使用多態(tài)性時(shí),不把析構(gòu)函數(shù)定義成虛函數(shù)所帶來(lái)的影響。這種錯(cuò)誤不會(huì)立刻使程序崩潰,但是它不知不覺(jué)中使內(nèi)存泄漏。

 

5.純虛析構(gòu)函數(shù)的應(yīng)用

在一些時(shí)候,我們需要定義一個(gè)抽象類,但是剛好沒(méi)有其他純虛函數(shù),這時(shí)候我們不妨將析構(gòu)函數(shù)定義為純虛的,因?yàn)樽鳛榛惖奈鰳?gòu)函數(shù)本來(lái)就要求為虛函數(shù),將其進(jìn)一步定義為純虛函數(shù)并無(wú)太大不同。唯一需要注意的是,定義純虛析構(gòu)函數(shù)時(shí)必須為其提供函數(shù)體,如下。

class a{
public:
virtual ~a() = 0;
};
a::~a(){ }

class b:public a{
//不一定需要重定義析構(gòu)函數(shù),根據(jù)需要
}

還要注意一點(diǎn),在析構(gòu)函數(shù)中,虛機(jī)制也是不存在的,可通過(guò)下面的代碼體會(huì)。

#include<iostream>
using namespace std;
class base{
public:
virtual ~base(){cout<<"~base()"<<endl;f();}
virtual void f(){cout<<"base::f()"<<endl;}
};
class derived : public base{
public:
~derived(){cout<<"~derived()"<<endl;}
void f(){cout<<"derived::f()"<<endl;}
};
int main(){
base * pb = new derived();
delete pb;
}

控制臺(tái)輸出為:

~derived()
~base()
base::f()

以上就是深入解析c++中多態(tài)性和虛函數(shù)使用原理的詳細(xì)內(nèi)容,更多關(guān)于c++多態(tài)性虛函數(shù)的資料請(qǐng)關(guān)注碩編程其它相關(guān)文章!

下一節(jié):linux/c++多線程實(shí)例學(xué)習(xí)十字路口車輛調(diào)度

c語(yǔ)言編程技術(shù)

相關(guān)文章