亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入解析C++編程中的純虛函數(shù)和抽象類

 更新時間:2015年09月23日 15:32:35   投稿:goldensun  
這篇文章主要介紹了深入解析C++編程中的純虛函數(shù)和抽象類,是C++入門學習中的基礎知識,需要的朋友可以參考下

C++純虛函數(shù)詳解

有時在基類中將某一成員函數(shù)定為虛函數(shù),并不是基類本身的要求,而是考慮到派生類的需要,在基類中預留了一個函數(shù)名,具體功能留給派生類根據(jù)需要去定義。

純虛函數(shù)是在聲明虛函數(shù)時被“初始化”為0的函數(shù)。聲明純虛函數(shù)的一般形式是

  virtual 函數(shù)類型 函數(shù)名 (參數(shù)表列) = 0;

關于純虛函數(shù)需要注意的幾點:

  • 純虛函數(shù)沒有函數(shù)體;
  • 最后面的“=0”并不表示函數(shù)返回值為0,它只起形式上的作用,告訴編譯系統(tǒng)“這是純虛函數(shù)”;
  • 這是一個聲明語句,最后應有分號。

純虛函數(shù)只有函數(shù)的名字而不具備函數(shù)的功能,不能被調(diào)用。它只是通知編譯系統(tǒng):“在這里聲明一個虛函數(shù),留待派生類中定義”。在派生類中對此函數(shù)提供定義后,它才能具備函數(shù)的功能,可被調(diào)用。

純虛函數(shù)的作用是在基類中為其派生類保留一個函數(shù)的名字,以便派生類根據(jù)需要對它進行定義。

如果在基類中沒有保留函數(shù)名字,則無法實現(xiàn)多態(tài)性。如果在一個類中聲明了純虛函數(shù),而在其派生類中沒有對該函數(shù)定義,則該虛函數(shù)在派生類中仍然為純虛函數(shù)。

再談C++抽象類

如果聲明了一個類,一般可以用它定義對象。但是在面向對象程序設計中,往往有一些類,它們不用來生成對象。定義這些類的惟一目的是用它作為基類去建立派生類。它們作為一種基本類型提供給用戶,用戶在這個基礎上根據(jù)自己的需要定義出功能各異的派生類。用這些派生類去建立對象。

打個比方,汽車制造廠往往向客戶提供卡車的底盤(包括發(fā)動機、傳動部分、車輪等),組裝廠可以把它組裝成貨車、公共汽車、工程車或客車等不同功能的車輛。底盤本身不是車輛,要經(jīng)過加工才能成為車輛,但它是車輛的基本組成部分。它相當于基類。在現(xiàn)代化的生產(chǎn)中,大多采用專業(yè)化的生產(chǎn)方式,充分利用專業(yè)化工廠生產(chǎn)的部件,加工集成為新品種的產(chǎn)品。生產(chǎn)公共汽車的廠家決不會從制造發(fā)動機到生產(chǎn)輪胎、制造車廂都由本廠完成。其實,不同品牌的電腦里面的基本部件是一樣的或相似的。這種觀念對軟件開發(fā)是十分重要的。一個優(yōu)秀的軟件工作者在開發(fā)一個大的軟件時,決不會從頭到尾都由自己編寫程序代碼,他會充分利用已有資源(例如類庫)作為自己工作的基礎。

這種不用來定義對象而只作為一種基本類型用作繼承的類,稱為抽象類(abstract class ),由于它常用作基類,通常稱為抽象基類(abstract base class )。凡是包含純虛函數(shù)的類都是抽象類。因為純虛函數(shù)是不能被調(diào)用的,包含純虛函數(shù)的類是無法建立對象的。

抽象類的作用是作為一個類族的共同基類,或者說,為一個類族提供一個公共接口。一個類層次結構中當然也可不包含任何抽象類,每一層次的類都是實際可用的,可以用來建立對象的。

但是,許多好的面向對象的系統(tǒng),其層次結構的頂部是一個抽象類,甚至頂部有好幾層都是抽象類。

如果在抽象類所派生出的新類中對基類的所有純虛函數(shù)進行了定義,那么這些函數(shù)就被賦予了功能,可以被調(diào)用。這個派生類就不是抽象類,而是可以用來定義對象的具體類(concrete class )。

如果在派生類中沒有對所有純虛函數(shù)進行定義,則此派生類仍然是抽象類,不能用來定義對象。雖然抽象類不能定義對象(或者說抽象類不能實例化),但是可以定義指向抽象類數(shù)據(jù)的指針變量。當派生類成為具體類之后,就可以用這種指針指向派生類對象,然后通過該指針調(diào)用虛函數(shù),實現(xiàn)多態(tài)性的操作。

幾個關于C++純虛函數(shù)與抽象類的實例
下面是一個完整的程序,為了便于閱讀,分段插入了一些文字說明。程序如下:

第(1)部分

#include <iostream>
using namespace std;
//聲明抽象基類Shape
class Shape
{
public:
  virtual float area( )const {return 0.0;} //虛函數(shù)
  virtual float volume()const {return 0.0;} //虛函數(shù)
  virtual void shapeName()const =0; //純虛函數(shù)
};

Shape類有3個成員函數(shù),沒有數(shù)據(jù)成員。3個成員函數(shù)都聲明為虛函數(shù),其中shapeName聲明為純虛函數(shù),因此Shape是一個抽象基類。shapeName函數(shù)的作用是輸出具體的形狀(如點、圓、圓柱體)的名字,這個信息是與相應的派生類密切相關的,顯然這不應當在基類中定義,而應在派生類中定義。所以把它聲明為純虛函數(shù)。Shape雖然是抽象基類,但是也可以包括某些成員的定義部分。類中兩個函數(shù)area(面積)和volume (體積)包括函數(shù)體,使其返回值為0(因為可以認為點的面積和體積都為0)。由于考慮到在Point類中不再對area和volume函數(shù)重新定義,因此沒有把area和volume函數(shù)也聲明為純虛函數(shù)。在Point類中繼承了Shape類的area和volume函數(shù)。這3個函數(shù)在各派生類中都要用到。

第(2)部分

//聲明Point類
class Point:public Shape//Point是Shape的公用派生類
{
public:
  Point(float=0,float=0);
  void setPoint(float ,float );
  float getX( )const {return x;}
  float getY( )const {return y;}
  virtual void shapeName( )const {cout<<"Point:";}//對虛函數(shù)進行再定義
  friend ostream & operator <<(ostream &,const Point &);
protected:
  float x,y;
};
//定義Point類成員函數(shù)
Point::Point(float a,float b)
{x=a;y=b;}
void Point::setPoint(float a,float b)
{x=a;y=b;}
ostream & operator <<(ostream &output,const Point &p)
{
  output<<"["<<p.x<<","<<p.y<<"]";
  return output;
}

Point從Shape繼承了3個成員函數(shù),由于“點”是沒有面積和體積的,因此不必重新定義area和volume。雖然在Point類中用不到這兩個函數(shù),但是Point類仍然從Shape類繼承了這兩個函數(shù),以便其派生類繼承它們。shapeName函數(shù)在Shape類中是純虛函數(shù), 在Point類中要進行定義。Point類還有自己的成員函數(shù)( setPoint, getX, getY)和數(shù)據(jù)成 員(x和y)。

第(3)部分

//聲明Circle類
class Circle:public Point
{
public:
  Circle(float x=0,float y=0,float r=0);
  void setRadius(float );
  float getRadius( )const;
  virtual float area( )const;
  virtual void shapeName( )const {cout<<"Circle:";}//對虛函數(shù)進行再定義
  friend ostream &operator <<(ostream &,const Circle &);
protected:
  float radius;
};
//聲明Circle類成員函數(shù)
Circle::Circle(float a,float b,float r):Point(a,b),radius(r){}
void Circle::setRadius(float r):radius(r){}
float Circle::getRadius( )const {return radius;}
float Circle::area( )const {return 3.14159*radius*radius;}
ostream &operator <<(ostream &output,const Circle &c)
{
  output<<"["<<c.x<<","<<c.y<<"], r="<<c.radius;
  return output;
}

在Circle類中要重新定義area函數(shù),因為需要指定求圓面積的公式。由于圓沒有體積,因此不必重新定義volume函數(shù),而是從Point類繼承volume函數(shù)。shapeName函數(shù)是虛函數(shù),需要重新定義,賦予新的內(nèi)容(如果不重新定義,就會繼承Point類中的 shapeName函數(shù))。此外,Circle類還有自己新增加的成員函數(shù)(setRadius, getRadius)和數(shù)據(jù)成員(radius)。

第(4)部分

//聲明Cylinder類
class Cylinder:public Circle
{
public:
  Cylinder (float x=0,float y=0,float r=0,float h=0);
  void setHeight(float );
  virtual float area( )const;
  virtual float volume( )const;
  virtual void shapeName( )const {
   cout<<"Cylinder:";
  }//對虛函數(shù)進行再定義
  friend ostream& operator <<(ostream&,const Cylinder&);
protected:
  float height;
};
//定義Cylinder類成員函數(shù)
Cylinder::Cylinder(float a,float b,float r,float h):Circle(a,b,r),height(h){}
void Cylinder::setHeight(float h){height=h;}
float Cylinder::area( )const{
  return 2*Circle::area( )+2*3.14159*radius*height;
}
float Cylinder::volume( )const{
  return Circle::area( )*height;
}
ostream &operator <<(ostream &output,const Cylinder& cy){
  output<<"["<<cy.x<<","<<cy.y<<"], r="<<cy.radius<<", h="<<cy.height;
  return output;
}

Cylinder類是從Circle類派生的。由于圓柱體有表面積和體積,所以要對area和 volume函數(shù)重新定義。虛函數(shù)shapeName也需要重新定義。此外,Cylinder類還有自已 的成員函數(shù)setHeight和數(shù)據(jù)成員radius。

第(5)部分

//main函數(shù)
int main( )
{
  Point point(3.2,4.5); //建立Point類對象point
  Circle circle(2.4,1.2,5.6);
  //建立Circle類對象circle
  Cylinder cylinder(3.5,6.4,5.2,10.5);
  //建立Cylinder類對象cylinder
  point.shapeName();
  //靜態(tài)關聯(lián)
  cout<<point<<endl;
  circle.shapeName(); //靜態(tài)關聯(lián)
  cout<<circle<<endl;
  cylinder.shapeName(); //靜態(tài)關聯(lián)
  cout<<cylinder<<endl<<endl;
  Shape *pt; //定義基類指針
  pt=&point; //指針指向Point類對象
  pt->shapeName( ); //動態(tài)關聯(lián)
  cout<<"x="<<point.getX( )<<",y="<<point.getY( )<<"\narea="<<pt->area( )
   <<"\nvolume="<<pt->volume()<<"\n\n";
  pt=&circle; //指針指向Circle類對象
  pt->shapeName( ); //動態(tài)關聯(lián)
  cout<<"x="<<circle.getX( )<<",y="<<circle.getY( )<<"\narea="<<pt->area( )
   <<"\nvolume="<<pt->volume( )<<"\n\n";
  pt=&cylinder; //指針指向Cylinder類對象
  pt->shapeName( ); //動態(tài)關聯(lián)
  cout<<"x="<<cylinder.getX( )<<",y="<<cylinder.getY( )<<"\narea="<<pt->area( )
   <<"\nvolume="<<pt->volume( )<<"\n\n";
  return 0;
}

在主函數(shù)中調(diào)用有關函數(shù)并輸出結果。先分別定義了 Point類對象point,Circle類對象circle和Cylinder類對象cylinder。然后分別通過對象名point, circle和cylinder調(diào)用 了shapeNanme函數(shù),這是屬于靜態(tài)關聯(lián),在編譯階段就能確定應調(diào)用哪一個類的 shapeName函數(shù)。同時用重載的運箅符“<<”來輸出各對象的信息,可以驗證對象初始化是否正確。

再定義一個指向基類Shape對象的指針變量pt,使它先后指向3個派生類對象 point, Circle和cylinder,然后通過指針調(diào)用各函數(shù),如 pt->shapeName( ),pt ->area(), pt->volume( )。這時是通過動態(tài)關聯(lián)分別確定應該調(diào)用哪個函數(shù)。分別輸出不同類對象的信息。

程序運行結果如下:

Point:[3.2,4.5](Point類對象point的數(shù)據(jù):點的坐標)
Circle:[2.4,1.2], r=5.6 (Circle類對象circle的數(shù)據(jù):圓心和半徑)
Cylinder:[3.5,6.4], r=5.5, h=10.5 (Cylinder類對象cylinder的數(shù)據(jù): 圓心、半徑和高)

Point:x=3.2,y=4.5 (輸出Point類對象point的數(shù)據(jù):點的坐標)
area=0 (點的面積)
volume=0 (點的體積)

Circle:x=2.4,y=1.2 (輸出Circle類對象circle的數(shù)據(jù):圓心坐標)
area=98.5203 (圓的面積)
volume=0 (圓的體積)
Cylinder:x=3.5,y=6.4 (輸出Cylinder類對象cylinder的數(shù)據(jù):圓心坐標)
area=512.595 (圓的面積)
volume=891.96 (圓柱的體積)

從本例可以進一步明確以下結論:
一個基類如果包含一個或一個以上純虛函數(shù),就是抽象基類。抽象基類不能也不必要定義對象。
抽象基類與普通基類不同,它一般并不是現(xiàn)實存在的對象的抽象(例如圓形(Circle)就是千千萬萬個實際的圓的抽象),它可以沒有任何物理上的或其他實際意義方面的含義。
在類的層次結構中,頂層或最上面的幾層可以是抽象基類。抽象基類體現(xiàn)了本類族中各類的共性,把各類中共有的成員函數(shù)集中在抽象基類中聲明。
抽象基類是本類族的公共接口?;蛘哒f,從同一基類派生出的多個類有同一接口。
區(qū)別靜態(tài)關聯(lián)和動態(tài)關聯(lián)。如果是通過對象名調(diào)用虛函數(shù)(如point.shapeName()),在編譯階段就能確定調(diào)用的是哪一個類的虛函數(shù),所以屬于靜態(tài)關聯(lián)。 如果是通過基類指針調(diào)用虛函數(shù)(如pt ->shapeName()),在編譯階段無法從語句本身確定調(diào)用哪一個類的虛函數(shù),只有在運行時,pt指向某一類對象后,才能確定調(diào)用的是哪 一個類的虛函數(shù),故為動態(tài)關聯(lián)。
如果在基類聲明了虛函數(shù),則在派生類中凡是與該函數(shù)有相同的函數(shù)名、函數(shù)類型、參數(shù)個數(shù)和類型的函數(shù),均為虛函數(shù)(不論在派生類中是否用virtual聲明)。
使用虛函數(shù)提高了程序的可擴充性。把類的聲明與類的使用分離。這對于設計類庫的軟件開發(fā)商來說尤為重要。

開發(fā)商設計了各種各樣的類,但不向用戶提供源代碼,用戶可以不知道類是怎樣聲明的,但是可以使用這些類來派生出自己的類。利用虛函數(shù)和多態(tài)性,程序員的注意力集中在處理普遍性,而讓執(zhí)行環(huán)境處理特殊性。

多態(tài)性把操作的細節(jié)留給類的設計者(他們多為專業(yè)人員)去完成,而讓程序人員(類的使用者)只需要做一些宏觀性的工作,告訴系統(tǒng)做什么,而不必考慮怎么做,極大地簡化了應用程序的編碼工作,大大減輕了程序員的負擔,也降低了學習和使用C++編程的難度,使更多的人能更快地進入C++程序設計的大門。

相關文章

  • opencv實現(xiàn)機器視覺檢測和計數(shù)的方法

    opencv實現(xiàn)機器視覺檢測和計數(shù)的方法

    在機器視覺中,有時需要對產(chǎn)品進行檢測和計數(shù)。其難點無非是對于產(chǎn)品的圖像分割。本文就來介紹一下機器視覺檢測和計數(shù)的實現(xiàn),感興趣的可以參考一下
    2021-05-05
  • EasyC++模板重載

    EasyC++模板重載

    這篇文章主要介紹了C++模板重載,重載的模板的函數(shù)特征,也就是入?yún)⒌臄?shù)量和類型必須有所不同,下面我們講舉例說明此內(nèi)容,具有一定的參考價值,需要的小伙伴可以參考一下
    2021-12-12
  • C++實現(xiàn)LeetCode(10.正則表達式匹配)

    C++實現(xiàn)LeetCode(10.正則表達式匹配)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(10.正則表達式匹配),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Qt使用QPainter實現(xiàn)自定義圓形進度條

    Qt使用QPainter實現(xiàn)自定義圓形進度條

    這篇文章主要介紹了Qt如何使用QPainter實現(xiàn)自定義圓形進度條功能,文中的示例代碼講解詳細,對我們學習Qt有一定的幫助,需要的可以參考一下
    2022-06-06
  • C++11 學習筆記之std::function和bind綁定器

    C++11 學習筆記之std::function和bind綁定器

    這篇文章主要介紹了C++11 學習筆記之std::function和bind綁定器,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-07-07
  • C++函數(shù)指針的用法詳解

    C++函數(shù)指針的用法詳解

    這篇文章主要為大家介紹了C++函數(shù)指針的用法,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

    2022-01-01
  • c++ 判斷是64位還是32位系統(tǒng)的實例

    c++ 判斷是64位還是32位系統(tǒng)的實例

    這篇文章主要介紹了c++ 判斷是64位還是32位系統(tǒng)的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 基于Windows API分解路徑問題的詳解

    基于Windows API分解路徑問題的詳解

    本篇文章是對Windows API分解路徑進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • c語言如何實現(xiàn)DES加密解密

    c語言如何實現(xiàn)DES加密解密

    這篇文章主要介紹了c語言如何實現(xiàn)DES加密解密問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 解析C++編程中如何使用設計模式中的狀態(tài)模式結構

    解析C++編程中如何使用設計模式中的狀態(tài)模式結構

    這篇文章主要介紹了如何在C++編程中適用設計模式中的狀態(tài)模式結構,狀態(tài)模式強調(diào)將特定狀態(tài)相關的邏輯分散到一些類的狀態(tài)類中,需要的朋友可以參考下
    2016-03-03

最新評論