最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入理解C++的多態(tài)性

 更新時(shí)間:2013年05月23日 14:49:38   投稿:jingxian  
本篇文章是對(duì)C++的多態(tài)性進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下

C++編程語言是一款應(yīng)用廣泛,支持多種程序設(shè)計(jì)的計(jì)算機(jī)編程語言。我們今天就會(huì)為大家詳細(xì)介紹其中C++多態(tài)性的一些基本知識(shí),以方便大家在學(xué)習(xí)過程中對(duì)此能夠有一個(gè)充分的掌握。

多態(tài)性可以簡(jiǎn)單地概括為“一個(gè)接口,多種方法”,程序在運(yùn)行時(shí)才決定調(diào)用的函數(shù),它是面向?qū)ο缶幊填I(lǐng)域的核心概念。多態(tài)(polymorphisn),字面意思多種形狀。

C++多態(tài)性是通過虛函數(shù)來實(shí)現(xiàn)的,虛函數(shù)允許子類重新定義成員函數(shù),而子類重新定義父類的做法稱為覆蓋(override),或者稱為重寫。(這里我覺得要補(bǔ)充,重寫的話可以有兩種,直接重寫成員函數(shù)和重寫虛函數(shù),只有重寫了虛函數(shù)的才能算作是體現(xiàn)了C++多態(tài)性)而重載則是允許有多個(gè)同名的函數(shù),而這些函數(shù)的參數(shù)列表不同,允許參數(shù)個(gè)數(shù)不同,參數(shù)類型不同,或者兩者都不同。編譯器會(huì)根據(jù)這些函數(shù)的不同列表,將同名的函數(shù)的名稱做修飾,從而生成一些不同名稱的預(yù)處理函數(shù),來實(shí)現(xiàn)同名函數(shù)調(diào)用時(shí)的重載問題。但這并沒有體現(xiàn)多態(tài)性。

多態(tài)與非多態(tài)的實(shí)質(zhì)區(qū)別就是函數(shù)地址是早綁定還是晚綁定。如果函數(shù)的調(diào)用,在編譯器編譯期間就可以確定函數(shù)的調(diào)用地址,并生產(chǎn)代碼,是靜態(tài)的,就是說地址是早綁定的。而如果函數(shù)調(diào)用的地址不能在編譯器期間確定,需要在運(yùn)行時(shí)才確定,這就屬于晚綁定。

那么多態(tài)的作用是什么呢,封裝可以使得代碼模塊化,繼承可以擴(kuò)展已存在的代碼,他們的目的都是為了代碼重用。而多態(tài)的目的則是為了接口重用。也就是說,不論傳遞過來的究竟是那個(gè)類的對(duì)象,函數(shù)都能夠通過同一個(gè)接口調(diào)用到適應(yīng)各自對(duì)象的實(shí)現(xiàn)方法。

最常見的用法就是聲明基類的指針,利用該指針指向任意一個(gè)子類對(duì)象,調(diào)用相應(yīng)的虛函數(shù),可以根據(jù)指向的子類的不同而實(shí)現(xiàn)不同的方法。如果沒有使用虛函數(shù)的話,即沒有利用C++多態(tài)性,則利用基類指針調(diào)用相應(yīng)的函數(shù)的時(shí)候,將總被限制在基類函數(shù)本身,而無法調(diào)用到子類中被重寫過的函數(shù)。因?yàn)闆]有多態(tài)性,函數(shù)調(diào)用的地址將是一定的,而固定的地址將始終調(diào)用到同一個(gè)函數(shù),這就無法實(shí)現(xiàn)一個(gè)接口,多種方法的目的了。

筆試題目:

#include<iostream>
using namespace std;
class A
{
public:
 void foo()
 {
 printf("1\n");
 }
 virtual void fun()
 {
 printf("2\n");
 }
};
class B : public A
{
public:
 void foo()
 {
 printf("3\n");
 }
 void fun()
 {
 printf("4\n");
 }
};
int main(void)
{
 A a;
 B b;
 A *p = &a;
 p->foo();
 p->fun();
 p = &b;
 p->foo();
 p->fun();
 return 0;
}

第一個(gè)p->foo()和p->fuu()都很好理解,本身是基類指針,指向的又是基類對(duì)象,調(diào)用的都是基類本身的函數(shù),因此輸出結(jié)果就是1、2。

第二個(gè)輸出結(jié)果就是1、4。p->foo()和p->fuu()則是基類指針指向子類對(duì)象,正式體現(xiàn)多態(tài)的用法,p->foo()由于指針是個(gè)基類指針,指向是一個(gè)固定偏移量的函數(shù),因此此時(shí)指向的就只能是基類的foo()函數(shù)的代碼了,因此輸出的結(jié)果還是1。而p->fun()指針是基類指針,指向的fun是一個(gè)虛函數(shù),由于每個(gè)虛函數(shù)都有一個(gè)虛函數(shù)列表,此時(shí)p調(diào)用fun()并不是直接調(diào)用函數(shù),而是通過虛函數(shù)列表找到相應(yīng)的函數(shù)的地址,因此根據(jù)指向的對(duì)象不同,函數(shù)地址也將不同,這里將找到對(duì)應(yīng)的子類的fun()函數(shù)的地址,因此輸出的結(jié)果也會(huì)是子類的結(jié)果4。

筆試的題目中還有一個(gè)另類測(cè)試方法。即

B *ptr = (B *)&a;  ptr->foo();  ptr->fun();

問這兩調(diào)用的輸出結(jié)果。這是一個(gè)用子類的指針去指向一個(gè)強(qiáng)制轉(zhuǎn)換為子類地址的基類對(duì)象。結(jié)果,這兩句調(diào)用的輸出結(jié)果是3,2。
并不是很理解這種用法,從原理上來解釋,由于B是子類指針,雖然被賦予了基類對(duì)象地址,但是ptr->foo()在調(diào)用的時(shí)候,由于地址偏移量固定,偏移量是子類對(duì)象的偏移量,于是即使在指向了一個(gè)基類對(duì)象的情況下,還是調(diào)用到了子類的函數(shù),雖然可能從始到終都沒有子類對(duì)象的實(shí)例化出現(xiàn)。
而ptr->fun()的調(diào)用,可能還是因?yàn)镃++多態(tài)性的原因,由于指向的是一個(gè)基類對(duì)象,通過虛函數(shù)列表的引用,找到了基類中fun()函數(shù)的地址,因此調(diào)用了基類的函數(shù)。由此可見多態(tài)性的強(qiáng)大,可以適應(yīng)各種變化,不論指針是基類的還是子類的,都能找到正確的實(shí)現(xiàn)方法。

//小結(jié):1、有virtual才可能發(fā)生多態(tài)現(xiàn)象
// 2、不發(fā)生多態(tài)(無virtual)調(diào)用就按原類型調(diào)用
#include<iostream>
using namespace std;
class Base
{
public:
 virtual void f(float x)
 {
 cout<<"Base::f(float)"<< x <<endl;
 }
 void g(float x)
 {
 cout<<"Base::g(float)"<< x <<endl;
 }
 void h(float x)
 {
 cout<<"Base::h(float)"<< x <<endl;
 }
};
class Derived : public Base
{
public:
 virtual void f(float x)
 {
 cout<<"Derived::f(float)"<< x <<endl;  //多態(tài)、覆蓋
 }
 void g(int x)
 {
 cout<<"Derived::g(int)"<< x <<endl;   //隱藏
 }
 void h(float x)
 {
 cout<<"Derived::h(float)"<< x <<endl;  //隱藏
 }
};
int main(void)
{
 Derived d;
 Base *pb = &d;
 Derived *pd = &d;
 // Good : behavior depends solely on type of the object
 pb->f(3.14f);  // Derived::f(float) 3.14
 pd->f(3.14f);  // Derived::f(float) 3.14
 // Bad : behavior depends on type of the pointer
 pb->g(3.14f);  // Base::g(float) 3.14
 pd->g(3.14f);  // Derived::g(int) 3 
 // Bad : behavior depends on type of the pointer
 pb->h(3.14f);  // Base::h(float) 3.14
 pd->h(3.14f);  // Derived::h(float) 3.14
 return 0;
}

令人迷惑的隱藏規(guī)則

本來僅僅區(qū)別重載與覆蓋并不算困難,但是C++的隱藏規(guī)則使問題復(fù)雜性陡然增加。
這里“隱藏”是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù),規(guī)則如下:
(1)如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時(shí),不論有無virtual
關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。
(2)如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒有virtual
關(guān)鍵字。此時(shí),基類的函數(shù)被隱藏(注意別與覆蓋混淆)。
上面的程序中:
(1)函數(shù)Derived::f(float)覆蓋了Base::f(float)。
(2)函數(shù)Derived::g(int)隱藏了Base::g(float),而不是重載。
(3)函數(shù)Derived::h(float)隱藏了Base::h(float),而不是覆蓋。

C++純虛函數(shù)

一、定義
純虛函數(shù)是在基類中聲明的虛函數(shù),它在基類中沒有定義,但要求任何派生類都要定義自己的實(shí)現(xiàn)方法。在基類中實(shí)現(xiàn)純虛函數(shù)的方法是在函數(shù)原型后加“=0”
virtual void funtion()=0
二、引入原因
1、為了方便使用多態(tài)特性,我們常常需要在基類中定義虛擬函數(shù)。
2、在很多情況下,基類本身生成對(duì)象是不合情理的。例如,動(dòng)物作為一個(gè)基類可以派生出老虎、孔雀等子類,但動(dòng)物本身生成對(duì)象明顯不合常理。
為了解決上述問題,引入了純虛函數(shù)的概念,將函數(shù)定義為純虛函數(shù)(方法:virtual ReturnType Function()= 0;),則編譯器要求在派生類中必須予以重寫以實(shí)現(xiàn)多態(tài)性。同時(shí)含有純虛擬函數(shù)的類稱為抽象類,它不能生成對(duì)象。這樣就很好地解決了上述兩個(gè)問題。
三、相似概念
1、多態(tài)性
指相同對(duì)象收到不同消息或不同對(duì)象收到相同消息時(shí)產(chǎn)生不同的實(shí)現(xiàn)動(dòng)作。C++支持兩種多態(tài)性:編譯時(shí)多態(tài)性,運(yùn)行時(shí)多態(tài)性。
a、編譯時(shí)多態(tài)性:通過重載函數(shù)實(shí)現(xiàn)
b、運(yùn)行時(shí)多態(tài)性:通過虛函數(shù)實(shí)現(xiàn)。
2、虛函數(shù)
虛函數(shù)是在基類中被聲明為virtual,并在派生類中重新定義的成員函數(shù),可實(shí)現(xiàn)成員函數(shù)的動(dòng)態(tài)覆蓋(Override)
3、抽象類
包含純虛函數(shù)的類稱為抽象類。由于抽象類包含了沒有定義的純虛函數(shù),所以不能定義抽象類的對(duì)象。

相關(guān)文章

  • C語言常見的文件操作函數(shù)

    C語言常見的文件操作函數(shù)

    這篇文章主要為大家介紹了C語言文件操作函數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • 基于QT實(shí)現(xiàn)文件上傳和下載功能

    基于QT實(shí)現(xiàn)文件上傳和下載功能

    這篇文章主要為大家詳細(xì)介紹了基于QT實(shí)現(xiàn)文件上傳和下載功能,支持?jǐn)帱c(diǎn)續(xù)傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Qt連接數(shù)據(jù)庫并實(shí)現(xiàn)數(shù)據(jù)庫增刪改查的圖文教程

    Qt連接數(shù)據(jù)庫并實(shí)現(xiàn)數(shù)據(jù)庫增刪改查的圖文教程

    QT連接數(shù)據(jù)庫是應(yīng)用開發(fā)的常用基礎(chǔ)操作,經(jīng)過實(shí)驗(yàn)我總結(jié)了一些例程,下面這篇文章主要給大家介紹了關(guān)于Qt連接數(shù)據(jù)庫并實(shí)現(xiàn)數(shù)據(jù)庫增刪改查的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • C語言刪除輸入字符串中的空格示例代碼

    C語言刪除輸入字符串中的空格示例代碼

    最近工作中遇到了需求,要?jiǎng)h除字符串中的所有空格,就要篩選出空格字符,這篇文章主要給大家介紹了關(guān)于利用C語言刪除輸入字符串中的空格的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • C++內(nèi)核對(duì)象封裝單實(shí)例啟動(dòng)程序的類

    C++內(nèi)核對(duì)象封裝單實(shí)例啟動(dòng)程序的類

    這篇文章主要介紹了利用C++內(nèi)核對(duì)象封裝的類,程序只能運(yùn)行單個(gè)實(shí)例,可防止多次啟動(dòng),大家參考使用吧
    2013-11-11
  • Qt使用QWT繪制柱狀圖詳解

    Qt使用QWT繪制柱狀圖詳解

    QT中提供了一個(gè)叫做QWT的庫。QWT,全稱是Qt?Widgets?for?Technical?Applications,是一個(gè)基于LGPL版權(quán)協(xié)議的開源項(xiàng)目,可生成各種統(tǒng)計(jì)圖。本文將通過它繪制柱狀圖,需要的可以參考一下
    2022-01-01
  • C++中opencv4.1.0環(huán)境配置的詳細(xì)過程

    C++中opencv4.1.0環(huán)境配置的詳細(xì)過程

    這篇文章主要介紹了C++中opencv4.1.0環(huán)境配置的詳細(xì)過程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • C++遞歸與分治算法原理示例詳解

    C++遞歸與分治算法原理示例詳解

    這篇文章主要為大家介紹了C++遞歸與分治算法的策略原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-11-11
  • 一文搞懂Codec2框架解析

    一文搞懂Codec2框架解析

    這篇文章主要介紹了Codec2框架解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • 深入了解C語言棧的創(chuàng)建

    深入了解C語言棧的創(chuàng)建

    棧只允許在一端進(jìn)行插入或刪除操作的線性表。首先棧是一種線性表,但是限定這種線性表只能在某一端進(jìn)行插入和刪除操作,這篇文章主要介紹了C語言對(duì)棧的實(shí)現(xiàn)基本操作
    2021-07-07

最新評(píng)論

红桥区| 长子县| 宜阳县| 于田县| 阿瓦提县| 台东市| 河南省| 兴义市| 三门峡市| 通化市| 呼和浩特市| 濮阳县| 四平市| 溧阳市| 安顺市| 淮北市| 大埔区| 巢湖市| 莲花县| 黄浦区| 玉溪市| 壶关县| 太原市| 蒙阴县| 葵青区| 镇江市| 名山县| 无极县| 遂平县| 岢岚县| 百色市| 拉孜县| 遵化市| 江北区| 芦山县| 池州市| 五峰| 三都| 营山县| 天全县| 准格尔旗|