程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深刻解析C++編程中的純虛函數和籠統類

深刻解析C++編程中的純虛函數和籠統類

編輯:關於C++

深刻解析C++編程中的純虛函數和籠統類。本站提示廣大學習愛好者:(深刻解析C++編程中的純虛函數和籠統類)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C++編程中的純虛函數和籠統類正文


C++純虛函數詳解

有時在基類中將某一成員函數定為虛函數,其實不是基類自己的請求,而是斟酌到派生類的須要,在基類中預留了一個函數名,詳細功效留給派生類依據須要去界說。

純虛函數是在聲明虛函數時被“初始化”為0的函數。聲明純虛函數的普通情勢是

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

關於純虛函數須要留意的幾點:

  • 純虛函數沒有函數體;
  • 最初面的“=0”其實不表現函數前往值為0,它只起情勢上的感化,告知編譯體系“這是純虛函數”;
  • 這是一個聲明語句,最初應有分號。

純虛函數只要函數的名字而不具有函數的功效,不克不及被挪用。它只是告訴編譯體系:“在這裡聲明一個虛函數,留待派生類中界說”。在派生類中對此函數供給界說後,它能力具有函數的功效,可被挪用。

純虛函數的感化是在基類中為其派生類保存一個函數的名字,以便派生類依據須要對它停止界說。

假如在基類中沒有保存函數名字,則沒法完成多態性。假如在一個類中聲清楚明了純虛函數,而在其派生類中沒有對該函數界說,則該虛函數在派生類中依然為純虛函數。

再談C++籠統類

假如聲清楚明了一個類,普通可以用它界說對象。然則在面向對象法式設計中,常常有一些類,它們不消來生成對象。界說這些類的唯一目標是用它作為基類去樹立派生類。它們作為一種根本類型供給給用戶,用戶在這個基本上依據本身的須要界說出功效各別的派生類。用這些派生類去樹立對象。

打個比喻,汽車制作廠常常向客戶供給卡車的底盤(包含動員機、傳動部門、車輪等),組裝廠可以把它組裝成貨車、公共汽車、工程車或客車等分歧功效的車輛。底盤自己不是車輛,要經由加工能力成為車輛,但它是車輛的根本構成部門。它相當於基類。在古代化的臨盆中,年夜多采取專業化的臨盆方法,充足應用專業化工場臨盆的部件,加工集成為新種類的產物。臨盆公共汽車的廠家決不會從制作動員機到臨盆輪胎、制作車箱都由本廠完成。其實,分歧品牌的電腦外面的根本部件是一樣的或類似的。這類不雅念對軟件開辟是非常主要的。一個優良的軟件任務者在開辟一個年夜的軟件時,決不會從頭至尾都由本身編寫法式代碼,他會充足應用已有資本(例如類庫)作為本身任務的基本。

這類不消來界說對象而只作為一種根本類型用作繼續的類,稱為籠統類(abstract class ),因為它經常使用作基類,平日稱為籠統基類(abstract base class )。但凡包括純虛函數的類都是籠統類。由於純虛函數是不克不及被挪用的,包括純虛函數的類是沒法樹立對象的。

籠統類的感化是作為一個類族的配合基類,或許說,為一個類族供給一個公共接口。一個類條理構造中固然也可不包括任何籠統類,每條理的類都是現實可用的,可以用來樹立對象的。

然則,很多好的面向對象的體系,其條理構造的頂部是一個籠統類,乃至頂部有好幾層都是籠統類。

假如在籠統類所派生出的新類中對基類的一切純虛函數停止了界說,那末這些函數就被付與了功效,可以被挪用。這個派生類就不是籠統類,而是可以用來界說對象的詳細類(concrete class )。

假如在派生類中沒有對一切純虛函數停止界說,則此派生類依然是籠統類,不克不及用來界說對象。固然籠統類不克不及界說對象(或許說籠統類不克不及實例化),然則可以界說指向籠統類數據的指針變量。當派生類成為詳細類以後,便可以用這類指針指向派生類對象,然後經由過程該指針挪用虛函數,完成多態性的操作。

幾個關於C++純虛函數與籠統類的實例
上面是一個完全的法式,為了便於浏覽,分段拔出了一些文字解釋。法式以下:

第(1)部門

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

Shape類有3個成員函數,沒稀有據成員。3個成員函數都聲明為虛函數,個中shapeName聲明為純虛函數,是以Shape是一個籠統基類。shapeName函數的感化是輸入詳細的外形(如點、圓、圓柱體)的名字,這個信息是與響應的派生類親密相干的,明顯這不該當在基類中界說,而應在派生類中界說。所以把它聲明為純虛函數。Shape固然是籠統基類,然則也能夠包含某些成員的界說部門。類中兩個函數area(面積)和volume (體積)包含函數體,使其前往值為0(由於可以以為點的面積和體積都為0)。因為斟酌到在Point類中不再對area和volume函數從新界說,是以沒有把area和volume函數也聲明為純虛函數。在Point類中繼續了Shape類的area和volume函數。這3個函數在各派生類中都要用到。

第(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:";}//對虛函數停止再界說
  friend ostream & operator <<(ostream &,const Point &);
protected:
  float x,y;
};
//界說Point類成員函數
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個成員函數,因為“點”是沒有面積和體積的,是以不用從新界說area和volume。固然在Point類頂用不到這兩個函數,然則Point類依然從Shape類繼續了這兩個函數,以便其派生類繼續它們。shapeName函數在Shape類中是純虛函數, 在Point類中要停止界說。Point類還有本身的成員函數( setPoint, getX, getY)和數據成 員(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:";}//對虛函數停止再界說
  friend ostream &operator <<(ostream &,const Circle &);
protected:
  float radius;
};
//聲明Circle類成員函數
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函數,由於須要指定求圓面積的公式。因為圓沒有體積,是以不用從新界說volume函數,而是從Point類繼續volume函數。shapeName函數是虛函數,須要從新界說,付與新的內容(假如不從新界說,就會繼續Point類中的 shapeName函數)。另外,Circle類還有本身新增長的成員函數(setRadius, getRadius)和數據成員(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:";
  }//對虛函數停止再界說
  friend ostream& operator <<(ostream&,const Cylinder&);
protected:
  float height;
};
//界說Cylinder類成員函數
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函數從新界說。虛函數shapeName也須要從新界說。另外,Cylinder類還有自已 的成員函數setHeight和數據成員radius。

第(5)部門

//main函數
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();
  //靜態聯系關系
  cout<<point<<endl;
  circle.shapeName(); //靜態聯系關系
  cout<<circle<<endl;
  cylinder.shapeName(); //靜態聯系關系
  cout<<cylinder<<endl<<endl;
  Shape *pt; //界說基類指針
  pt=&point; //指針指向Point類對象
  pt->shapeName( ); //靜態聯系關系
  cout<<"x="<<point.getX( )<<",y="<<point.getY( )<<"\narea="<<pt->area( )
   <<"\nvolume="<<pt->volume()<<"\n\n";
  pt=&circle; //指針指向Circle類對象
  pt->shapeName( ); //靜態聯系關系
  cout<<"x="<<circle.getX( )<<",y="<<circle.getY( )<<"\narea="<<pt->area( )
   <<"\nvolume="<<pt->volume( )<<"\n\n";
  pt=&cylinder; //指針指向Cylinder類對象
  pt->shapeName( ); //靜態聯系關系
  cout<<"x="<<cylinder.getX( )<<",y="<<cylinder.getY( )<<"\narea="<<pt->area( )
   <<"\nvolume="<<pt->volume( )<<"\n\n";
  return 0;
}

在主函數中挪用有關函數並輸入成果。先分離界說了 Point類對象point,Circle類對象circle和Cylinder類對象cylinder。然後分離經由過程對象名point, circle和cylinder挪用 了shapeNanme函數,這是屬於靜態聯系關系,在編譯階段就可以肯定應挪用哪個類的 shapeName函數。同時用重載的運箅符“<<”來輸入各對象的信息,可以驗證對象初始化能否准確。

再界說一個指向基類Shape對象的指針變量pt,使它前後指向3個派生類對象 point, Circle和cylinder,然後經由過程指針挪用各函數,如 pt->shapeName( ),pt ->area(), pt->volume( )。這時候是經由過程靜態聯系關系分離肯定應當挪用哪一個函數。分離輸入分歧類對象的信息。

法式運轉成果以下:

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

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

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

從本例可以進一步明白以下結論:
一個基類假如包括一個或一個以上純虛函數,就是籠統基類。籠統基類不克不及也不用要界說對象。
籠統基類與通俗基類分歧,它普通其實不是實際存在的對象的籠統(例如圓形(Circle)就是千萬萬萬個現實的圓的籠統),它可以沒有任何物理上的或其他現實意義方面的寄義。
在類的條理構造中,頂層或最下面的幾層可所以籠統基類。籠統基類表現了本類族中各類的個性,把各類中共有的成員函數集中在籠統基類中聲明。
籠統基類是本類族的公共接口。或許說,從統一基類派生出的多個類有統一接口。
差別靜態聯系關系和靜態聯系關系。假如是經由過程對象名挪用虛函數(如point.shapeName()),在編譯階段就可以肯定挪用的是哪個類的虛函數,所以屬於靜態聯系關系。 假如是經由過程基類指針挪用虛函數(如pt ->shapeName()),在編譯階段沒法從語句自己肯定挪用哪個類的虛函數,只要在運轉時,pt指向某一類對象後,能力肯定挪用的是哪 一個類的虛函數,故為靜態聯系關系。
假如在基類聲清楚明了虛函數,則在派生類中但凡與該函數有雷同的函數名、函數類型、參數個數和類型的函數,均為虛函數(豈論在派生類中能否用virtual聲明)。
應用虛函數進步了法式的可擴大性。把類的聲明與類的應用分別。這關於設計類庫的軟件開辟商來講尤其主要。

開辟商設計了各類各樣的類,但不向用戶供給源代碼,用戶可以不曉得類是如何聲明的,然則可使用這些類來派生出本身的類。應用虛函數和多態性,法式員的留意力集中在處置廣泛性,而讓履行情況處置特別性。

多態性把操作的細節留給類的設計者(他們多為專業人員)去完成,而讓法式人員(類的應用者)只須要做一些微觀性的任務,告知體系做甚麼,而不用斟酌怎樣做,極年夜地簡化了運用法式的編碼任務,年夜年夜加重了法式員的累贅,也下降了進修和應用C++編程的難度,使更多的人能更快地進入C++法式設計的年夜門。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved