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

詳解C++編程的多態(tài)性概念

 更新時間:2015年09月22日 18:38:52   投稿:goldensun  
這篇文章主要介紹了C++編程的多態(tài)性概念,是C++入門學習中的基礎知識,需要的朋友可以參考下

多態(tài)性(polymorphism)是面向?qū)ο蟪绦蛟O計的一個重要特征。如果一種語言只支持類而不支持多態(tài),是不能被稱為面向?qū)ο笳Z言的,只能說是基于對象的,如Ada、VB就屬此類。C++支持多態(tài)性,在C++程序設計中能夠?qū)崿F(xiàn)多態(tài)性。利用多態(tài)性可以設計和實現(xiàn)一個易于擴展的系統(tǒng)。

顧名思義,多態(tài)的意思是一個事物有多種形態(tài)。多態(tài)性的英文單詞polymorphism來源于希臘詞根poly(意為“很多”)和morph(意為“形態(tài)”)。在C ++程序設計中,多態(tài)性是指具有不同功能的函數(shù)可以用同一個函數(shù)名,這樣就可以用一個函數(shù)名調(diào)用不同內(nèi)容的函數(shù)。在面向?qū)ο蠓椒ㄖ幸话闶沁@樣表述多態(tài)性的:向不同的對象發(fā)送同一個消息, 不同的對象在接收時會產(chǎn)生不同的行為(即方法)。也就是說,每個對象可以用自己的方式去響應共同的消息。所謂消息,就是調(diào)用函數(shù),不同的行為就是指不同的實現(xiàn),即執(zhí)行不同的函數(shù)。

其實,我們已經(jīng)多次接觸過多態(tài)性的現(xiàn)象,例如函數(shù)的重載、運算符重載都是多態(tài)現(xiàn)象。只是那時沒有用到多態(tài)性這一專門術語而已。例如,使用運算符“+”使兩個數(shù)值相加,就是發(fā)送一個消息,它要調(diào)用operator +函數(shù)。實際上,整型、單精度型、雙精度型的加法操作過程是互不相同的,是由不同內(nèi)容的函數(shù)實現(xiàn)的。顯然,它們以不同的行為或方法來響應同一消息。

在現(xiàn)實生活中可以看到許多多態(tài)性的例子。如學校校長向社會發(fā)布一個消息:9月1日新學年開學。不同的對象會作出不同的響應:學生要準備好課本準時到校上課;家長要籌集學費;教師要備好課;后勤部門要準備好教室、宿舍和食堂……由于事先對各種人的任務已作了規(guī)定,因此,在得到同一個消息時,各種人都知道自己應當怎么做,這就是 多態(tài)性。可以設想,如果不利用多態(tài)性,那么校長就要分別給學生、家長、教師、后勤部門等許多不同的對象分別發(fā)通知,分別具體規(guī)定每一種人接到通知后應該怎么做。顯然這是一件十分復雜而細致的工作。一人包攬一切,吃力還不討好?,F(xiàn)在,利用了多態(tài)性機制,校長在發(fā)布消息時,不必一一具體考慮不同類型人員是怎樣執(zhí)行的。至于各類人員在接到消息后應氣做什么,并不是臨時決定的,而是學校的工作機制事先安排決定好的。校長只需不斷發(fā)布各種消息,各種人員就會按預定方案有條不紊地工作。

同樣,在C++程序設計中,在不同的類中定義了其響應消息的方法,那么使用這些類 時,不必考慮它們是什么類型,只要發(fā)布消息即可。正如在使用運算符“ ”時不必考慮相加的數(shù)值是整型、單精度型還是雙精度型,直接使用“+”,不論哪類數(shù)值都能實現(xiàn)相加??梢哉f這是以不變應萬變的方法,不論對象千變?nèi)f化,用戶都是用同一形式的信息去調(diào)用它們,使它們根據(jù)事先的安排作出反應。

從系統(tǒng)實現(xiàn)的角度看,多態(tài)性分為兩類:靜態(tài)多態(tài)性和動態(tài)多態(tài)性。以前學過的函數(shù)重載和運算符重載實現(xiàn)的多態(tài)性屬于靜態(tài)多態(tài)性,在程序編譯時系統(tǒng)就能決定調(diào)用的是哪個函數(shù),因此靜態(tài)多態(tài)性又稱編譯時的多態(tài)性。靜態(tài)多態(tài)性是通過函數(shù)的重載實現(xiàn)的(運算符重載實質(zhì)上也是函數(shù)重載)。動態(tài)多態(tài)性是在程序運行過程中才動態(tài)地確定操作所針對的對象。它又稱運行時的多態(tài)性。動態(tài)多態(tài)性是通過虛函數(shù)(Virtual fiinction)實現(xiàn)的。

下面是一個承上啟下的例子。一方面它是有關繼承和運算符重載內(nèi)容的綜合應用的例子,通過這個例子可以進一步融會貫通前面所學的內(nèi)容,另一方面又是作為討論多態(tài)性的一個基礎用例。

希望大家耐心、深入地閱讀和消化這個程序,弄清其中的每一個細節(jié)。

[例] 先建立一個Point(點)類,包含數(shù)據(jù)成員x,y(坐標點)。以它為基類,派生出一個Circle(圓)類,增加數(shù)據(jù)成員r(半徑),再以Circle類為直接基類,派生出一個Cylinder(圓柱體)類,再增加數(shù)據(jù)成員h(高)。要求編寫程序,重載運算符“<<”和“>>”,使之能用于輸出以上類對象。

這個例題難度不大,但程序很長。對于一個比較大的程序,應當分成若干步驟進行。先聲明基類,再聲明派生類,逐級進行,分步調(diào)試。

1) 聲明基類Point

類可寫出聲明基類Point的部分如下:

#include <iostream>
//聲明類Point
class Point
{
public:
 Point(float x=0,float y=0); //有默認參數(shù)的構造函數(shù)
 void setPoint(float ,float); //設置坐標值
 float getX( )const {return x;} //讀x坐標
 float getY( )const {return y;} //讀y坐標
 friend ostream & operator <<(ostream &,const Point &); //重載運算符“<<”
protected: //受保護成員
 float x, y;
};
//下面定義Point類的成員函數(shù)
Point::Point(float a,float b) //Point的構造函數(shù)
{ //對x,y初始化
 x=a;
 y=b;
}
void Point::setPoint(float a,float b) //設置x和y的坐標值
{ //為x,y賦新值
 x=a;
 y=b;
}
//重載運算符“<<”,使之能輸出點的坐標
ostream & operator <<(ostream &output, const Point &p)
{
 output<<"["<<p.x<<","<<p.y<<"]"<<endl;
 return output;
}

以上完成了基類Point類的聲明。

為了提高程序調(diào)試的效率,提倡對程序分步調(diào)試,不要將一個長的程序都寫完以后才統(tǒng)一調(diào)試,那樣在編譯時可能會同時出現(xiàn)大量的編譯錯誤,面對一個長的程序,程序人員往往難以迅速準確地找到出錯位置。要善于將一個大的程序分解為若干個文件,分別編譯,或者分步調(diào)試,先通過最基本的部分,再逐步擴充。

現(xiàn)在要對上面寫的基類聲明進行調(diào)試,檢查它是否有錯,為此要寫出main函數(shù)。實際上它是一個測試程序。

int main( )
{
 Point p(3.5,6.4); //建立Point類對象p
 cout<<"x="<<p.getX( )<<",y="<<p.getY( )<<endl; //輸出p的坐標值
 p.setPoint(8.5,6.8); //重新設置p的坐標值
 cout<<"p(new):"<<p<<endl; //用重載運算符“<<”輸出p點坐標
 return 0;
}

getX和getY函數(shù)聲明為常成員函數(shù),作用是只允許函數(shù)引用類中的數(shù)據(jù),而不允許修改它們,以保證類中數(shù)據(jù)的安全。數(shù)據(jù)成員x和y聲明為protected,這樣可以被派生類訪問(如果聲明為private,派生類是不能訪問的)。

程序編譯通過,運行結果為:

x=3.5,y=6.4
p(new):[8.5,6.8]

測試程序檢查了基類中各函數(shù)的功能,以及運算符重載的作用,證明程序是正確的。

2)聲明派生類Circle

在上面的基礎上,再寫出聲明派生類Circle的部分:

class Circle:public Point //circle是Point類的公用派生類
{
public:
Circle(float x=0,float y=0,float r=0); //構造函數(shù)
void setRadius(float ); //設置半徑值
float getRadius( )const; //讀取半徑值
float area ( )const; //計算圓面積
friend ostream &operator <<(ostream &,const Circle &); //重載運算符“<<”
private:
float radius;
};
//定義構造函數(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;
}
//重載運算符“<<”,使之按規(guī)定的形式輸出圓的信息
ostream &operator <<(ostream &output,const Circle &c)
{
 output<<"Center=["<<c.x<<","<<c.y<<"],r="<<c.radius<<",area="<<c.area( )<<endl;
 return output;
}

為了測試以上Circle類的定義,可以寫出下面的主函數(shù):

int main( )
{
Circle c(3.5,6.4,5.2); //建立Circle類對象c,并給定圓心坐標和半徑
cout<<"original circle:\\nx="<<c.getX()<<", y="<<c.getY()<<", r="<<c.getRadius( )<<", area="<<c.area( )<<endl; //輸出圓心坐標、半徑和面積
c.setRadius(7.5); //設置半徑值
c.setPoint(5,5); //設置圓心坐標值x,y
cout<<"new circle:\\n"<<c; //用重載運算符“<<”輸出圓對象的信息
Point &pRef=c; //pRef是Point類的引用變量,被c初始化
cout<<"pRef:"<<pRef; //輸出pRef的信息
return 0;
}

程序編譯通過,運行結果為:

original circle:(輸出原來的圓的數(shù)據(jù))
x=3.5, y=6.4, r=5.2, area=84.9486
new circle:(輸出修改后的圓的數(shù)據(jù))
Center=[5,5], r=7.5, area=176.714
pRef:[5,5] (輸出圓的圓心“點”的數(shù)據(jù))

可以看到,在Point類中聲明了一次運算符“ <<”重載函數(shù),在Circle類中又聲明了一次運算符“ <<”,兩次重載的運算符“<<”內(nèi)容是不同的,在編譯時編譯系統(tǒng)會根據(jù)輸出項的類型確定調(diào)用哪一個運算符重載函數(shù)。main函數(shù)第7行用“cout<< ”輸出c,調(diào)用的是在Circle類中聲明的運算符重載函數(shù)。

請注意main函數(shù)第8行:

 Point & pRef = c;

定義了 Point類的引用變量pRef,并用派生類Circle對象c對其初始化。前面我們已經(jīng)講過,派生類對象可以替代基類對象為基類對象的引用初始化或賦值(詳情請查看:C++基類與派生類的轉(zhuǎn)換)?,F(xiàn)在 Circle是Point的公用派生類,因此,pRef不能認為是c的別名,它得到了c的起始地址, 它只是c中基類部分的別名,與c中基類部分共享同一段存儲單元。所以用“cout<<pRef”輸出時,調(diào)用的不是在Circle中聲明的運算符重載函數(shù),而是在Point中聲明的運算符重載函數(shù),輸出的是“點”的信息,而不是“圓”的信息。

3) 聲明Circle的派生類Cylinder

前面已從基類Point派生出Circle類,現(xiàn)在再從Circle派生出Cylinder類。

class Cylinder:public Circle// Cylinder是Circle的公用派生類
{
public:
 Cylinder (float x=0,float y=0,float r=0,float h=0); //構造函數(shù)
 void setHeight(float ); //設置圓柱高
 float getHeight( )const; //讀取圓柱高
 loat area( )const; //計算圓表面積
 float volume( )const; //計算圓柱體積
 friend ostream& operator <<(ostream&,const Cylinder&); //重載運算符<<
protected:
 float height;//圓柱高
};
//定義構造函數(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::getHeight( )const {return height;}
//計算圓表面積
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<<"Center=["<<cy.x<<","<<cy.y<<"],r="<<cy.radius<<",h="<<cy.height <<"\\narea="<<cy.area( )<<", volume="<<cy.volume( )<<endl;
 return output;
} //重載運算符“<<”

可以寫出下面的主函數(shù):

int main( )
{
 Cylinder cy1(3.5,6.4,5.2,10);//定義Cylinder類對象cy1
 cout<<"\\noriginal cylinder:\\nx="<<cy1.getX( )<<", y="<<cy1.getY( )<<", r="
  <<cy1.getRadius( )<<", h="<<cy1.getHeight( )<<"\\narea="<<cy1.area()
  <<",volume="<<cy1.volume()<<endl;//用系統(tǒng)定義的運算符“<<”輸出cy1的數(shù)據(jù)
 cy1.setHeight(15);//設置圓柱高
 cy1.setRadius(7.5);//設置圓半徑
 cy1.setPoint(5,5);//設置圓心坐標值x,y
 cout<<"\\nnew cylinder:\\n"<<cy1;//用重載運算符“<<”輸出cy1的數(shù)據(jù)
 Point &pRef=cy1;//pRef是Point類對象的引用變量
 cout<<"\\npRef as a Point:"<<pRef;//pRef作為一個“點”輸出
 Circle &cRef=cy1;//cRef是Circle類對象的引用變量
 cout<<"\\ncRef as a Circle:"<<cRef;//cRef作為一個“圓”輸出
 return 0;
}

運行結果如下:

original cylinder:(輸出cy1的初始值)
x=3.5, y=6.4, r=5.2, h=10 (圓心坐標x,y。半徑r,高h)
area=496.623, volume=849.486 (圓柱表面積area和體積volume)
new cylinder: (輸出cy1的新值)
Center=[5,5], r=7.5, h=15 (以[5,5]形式輸出圓心坐標)
area=1060.29, volume=2650.72(圓柱表面積area和體積volume)
pRef as a Point:[5,5] (pRef作為一個“點”輸出)
cRef as a Circle:Center=[5,5], r=7.5, area=176.714(cRef作為一個“圓”輸出)

說明:在Cylinder類中定義了 area函數(shù),它與Circle類中的area函數(shù)同名,根據(jù)前面我們講解的同名覆蓋的原則(詳情請查看:C++多重繼承的二義性問題),cy1.area( ) 調(diào)用的是Cylinder類的area函數(shù)(求圓柱表面積),而不是Circle類的area函數(shù)(圓面積)。請注意,這兩個area函數(shù)不是重載函數(shù),它們不僅函數(shù)名相同,而且函數(shù)類型和參數(shù)個數(shù)都相同,兩個同名函數(shù)不在同 —個類中,而是分別在基類和派生類中,屬于同名覆蓋。重載函數(shù)的參數(shù)個數(shù)和參數(shù)類型必須至少有一者不同,否則系統(tǒng)無法確定調(diào)用哪一個函數(shù)。

main函數(shù)第9行用“cout<<cy1”來輸出cy1,此時調(diào)用的是在Cylinder類中聲明的重載運算符“<<”,按在重載時規(guī)定的方式輸出圓柱體cy1的有關數(shù)據(jù)。

main函數(shù)中最后4行的含義與在定義Circle類時的情況類似。pRef是Point類的引用變量,用cy1對其初始化,但它不是cy1的別名,只是cy1中基類Point部分的別名,在輸出pRef時是作為一個Point類對象輸出的,也就是說,它是一個“點”。同樣,cRef是Circle類的引用變量,用cy1對其初始化,但它只是cy1中的直接基類Circle部分的別名, 在輸出 cRef 時是作為Circle類對象輸出的,它是一個"圓”,而不是一個“圓柱體”。從輸 出的結果可以看出調(diào)用的是哪個運算符函數(shù)。

在本例中存在靜態(tài)多態(tài)性,這是運算符重載引起的(注意3個運算符函數(shù)是重載而不是同名覆蓋,因為有一個形參類型不同)??梢钥吹?,在編譯時編譯系統(tǒng)即可以判定應調(diào)用哪個重載運算符函數(shù)。

相關文章

  • C++中const應放在類型前還是后

    C++中const應放在類型前還是后

    之前遇到小伙伴問C++中const加在類型名前和變量名前的區(qū)別,今天給大家簡單分析下。
    2016-05-05
  • C語言關于時間復雜度詳解

    C語言關于時間復雜度詳解

    大家好,本篇文章主要講的是C語言關于時間復雜度詳解,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • C語言控制臺版2048小游戲

    C語言控制臺版2048小游戲

    本文給大家分享的是2則使用C語言控制臺編寫的2048小游戲,各有優(yōu)劣,小伙伴們對比著參考下吧。
    2015-03-03
  • C++?std::array實現(xiàn)編譯器排序

    C++?std::array實現(xiàn)編譯器排序

    這篇文章主要介紹了C++?std::array實現(xiàn)編譯器排序,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-06-06
  • C++操作SQLite簡明教程

    C++操作SQLite簡明教程

    這篇文章主要介紹了C++操作SQLite簡明教程,包含創(chuàng)建表、插入數(shù)據(jù)、查詢數(shù)據(jù)等常用操作,需要的朋友可以參考下
    2014-06-06
  • C語言 遞歸解決青蛙跳臺階問題

    C語言 遞歸解決青蛙跳臺階問題

    遞歸做為一種算法在程序設計語言中廣泛應用。基本含義&#8203;是指函數(shù)/過程/子程序在運行過程序中直接或間接調(diào)用自身而產(chǎn)生的重入現(xiàn)象。在計算機編程里,遞歸指的是一個過程:函數(shù)不斷引用自身,直到引用的對象已知
    2021-11-11
  • C語言變量類型的深入分析

    C語言變量類型的深入分析

    這篇文章主要介紹了C語言變量類型的深入分析的相關資料,需要的朋友可以參考下
    2017-07-07
  • C++繼承和動態(tài)內(nèi)存分配

    C++繼承和動態(tài)內(nèi)存分配

    這篇文章主要介紹了C++繼承和動態(tài)內(nèi)存分配,當我們的基類使用動態(tài)內(nèi)存分配,并且重新定義賦值和復制構造函數(shù),這會對派生類的實現(xiàn)有什么影響呢?我們帶罩疑問倆姐下面文章內(nèi)容吧
    2022-01-01
  • C語言實現(xiàn)旅游資訊管理系統(tǒng)

    C語言實現(xiàn)旅游資訊管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)旅游資訊管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • LoadLibrary深入案例詳解

    LoadLibrary深入案例詳解

    這篇文章主要介紹了LoadLibrary深入案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08

最新評論