欧美大屁股bbbbxxxx,狼人大香伊蕉国产www亚洲,男ji大巴进入女人的视频小说,男人把ji大巴放进女人免费视频,免费情侣作爱视频

歡迎來(lái)到入門教程網(wǎng)!

C語(yǔ)言

當(dāng)前位置:主頁(yè) > 軟件編程 > C語(yǔ)言 >

C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法

來(lái)源:本站原創(chuàng)|時(shí)間:2020-01-10|欄目:C語(yǔ)言|點(diǎn)擊: 次

1、什么是多態(tài)

多態(tài)性可以簡(jiǎn)單概括為“一個(gè)接口,多種行為”。

也就是說(shuō),向不同的對(duì)象發(fā)送同一個(gè)消息, 不同的對(duì)象在接收時(shí)會(huì)產(chǎn)生不同的行為(即方法)。也就是說(shuō),每個(gè)對(duì)象可以用自己的方式去響應(yīng)共同的消息。所謂消息,就是調(diào)用函數(shù),不同的行為就是指不同的實(shí)現(xiàn),即執(zhí)行不同的函數(shù)。這是一種泛型技術(shù),即用相同的代碼實(shí)現(xiàn)不同的動(dòng)作。這體現(xiàn)了面向?qū)ο缶幊痰膬?yōu)越性。

多態(tài)分為兩種:

(1)編譯時(shí)多態(tài):主要通過(guò)函數(shù)的重載和模板來(lái)實(shí)現(xiàn)。

(2)運(yùn)行時(shí)多態(tài):主要通過(guò)虛函數(shù)來(lái)實(shí)現(xiàn)。

2、幾個(gè)相關(guān)概念

(1)覆蓋、重寫(override)

override指基類的某個(gè)成員函數(shù)為虛函數(shù),派生類又定義一成員函數(shù),除函數(shù)體的其余部分都與基類的成員函數(shù)相同。注意,如果只是函數(shù)名相同,形參或返回類型不同的話,就不能稱為override,而是hide。

(2)重載(overload)

指同一個(gè)作用域出生多個(gè)函數(shù)名相同,但是形參不同的函數(shù)。編譯器在編譯的時(shí)候,通過(guò)實(shí)參的個(gè)數(shù)和類型,選擇最終調(diào)用的函數(shù)。

(3)隱藏(hide)

分為兩種:

1)局部變量或者函數(shù)隱藏了全局變量或者函數(shù)
2)派生類擁有和基類同名的成員函數(shù)或成員變量。

產(chǎn)生的結(jié)果:使全局或基類的變量、函數(shù)不可見(jiàn)。

3、幾個(gè)簡(jiǎn)單的例子

/****************************************************************************************************** 
* File:PolymorphismTest 
* Introduction:測(cè)試多態(tài)的一些特性。 
* Author:CoderCong
* Date:20141114 
* LastModifiedDate:20160113 
*******************************************************************************************************/ 
#include "stdafx.h" 
#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() //由于基類的foo函數(shù)并不是虛函數(shù),所以是隱藏,而不是重寫 
  { 
    printf("3\n"); 
  } 
  void fun() //重寫 
  { 
    printf("4\n"); 
  } 
}; 
int main(void) 
{ 
  A a; 
  B b; 
  A *p = &a; 
  p->foo(); //輸出1。 
  p->fun(); //輸出2。 
  p = &b; 
  p->foo(); //輸出1。因?yàn)閜是基類指針,p->foo指向一個(gè)具有固定偏移量的函數(shù)。也就是基類函數(shù) 
  p->fun(); //輸出4。多態(tài)。雖然p是基類指針,但實(shí)際上指向的是一個(gè)子類對(duì)象。p->fun指向的是一個(gè)虛函數(shù)。按照動(dòng)態(tài)類型,調(diào)用子類函數(shù)   
  return 0; 
}

4、運(yùn)行時(shí)多態(tài)以及虛函數(shù)的內(nèi)部實(shí)現(xiàn)

看了上邊幾個(gè)簡(jiǎn)單的例子,我恍然大悟,原來(lái)這就是多態(tài),這么簡(jiǎn)單,明白啦!

好,那我們?cè)倏匆粋€(gè)例子:

class A 
{ 
public: 
  virtual void FunA() 
  { 
    cout << "FunA1" << endl; 
  }; 
  virtual void FunAA() 
  { 
    cout << "FunA2" << endl; 
  } 
}; 
class B 
{ 
public: 
  virtual void FunB() 
  { 
    cout << "FunB" << endl; 
  } 
}; 
class C :public A, public B 
{ 
public: 
  virtual void FunA() 
  { 
    cout << "FunA1C" << endl; 
  }; 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
  C objC; 
  A *pA = &objC; 
  B *pB = &objC; 
  C *pC = &objC; 
 
  printf("%d %d\n", &objC, objC); 
  printf("%d %d\n", pA, *pA); 
  printf("%d %d\n", pB, *pB); 
  printf("%d %d\n", pC, *pC); 
 
  return 0; 
}

運(yùn)行結(jié)果:

5241376 1563032

5241376 1563032

5241380 1563256

5241376 1563032

細(xì)心的同志一定發(fā)現(xiàn)了pB出了問(wèn)題,為什么明明都是指向objC的指針,pB跟別人的值都不一樣呢?

是不是編譯器出了問(wèn)題呢?

當(dāng)然不是!我們先講結(jié)論:

(1)每一個(gè)含有虛函數(shù)的類,都會(huì)生成虛表(virtual table)。這個(gè)表,記錄了對(duì)象的動(dòng)態(tài)類型,決定了執(zhí)行此對(duì)象的虛成員函數(shù)的時(shí)候,真正執(zhí)行的那一個(gè)成員函數(shù)。

(2)對(duì)于有多個(gè)基類的類對(duì)象,會(huì)有多個(gè)虛表,每一個(gè)基類對(duì)應(yīng)一個(gè)虛表,同時(shí),虛表的順序和繼承時(shí)的順序相同。

(3)在每一個(gè)類對(duì)象所占用的內(nèi)存中,虛指針位于最前邊,每個(gè)虛指針指向?qū)?yīng)的虛表。

先從簡(jiǎn)單的單個(gè)基類說(shuō)起:

class A 
{ 
public: 
  virtual void FunA() 
  { 
    cout << "FunA1" << endl; 
  } 
  virtual void FunA2() 
  { 
    cout << "FunA2" << endl; 
  } 
}; 
 
class C :public A 
{ 
  virtual void FunA() 
  { 
    cout << "FunA1C" << endl; 
  }
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
  A *pA = new A; 
  C *pC = new C; 
  typedef void (*Fun)(void); 
 
  Fun fun= (Fun)*((int*)(*(int*)pA)); 
  fun();//pA指向的第一個(gè)函數(shù) 
  fun = (Fun)*((int*)(*(int*)pA) +1); 
  fun();//pA指向的第二個(gè)函數(shù) 
   
  fun = (Fun)*((int*)(*(int*)pC)); 
  fun();//pC指向的第一個(gè)函數(shù) 
  fun = (Fun)*((int*)(*(int*)pC) + 1); 
  fun();//pC指向的第二個(gè)函數(shù) 
  return 0; 
}

運(yùn)行結(jié)果:

FunA1
FunA2
FunA1C
FunA2
是不是有點(diǎn)暈?沒(méi)關(guān)系。我一點(diǎn)一點(diǎn)解釋:pA對(duì)應(yīng)一個(gè)A的對(duì)象,我們可以畫出這樣的一個(gè)表:
      
這就是對(duì)象*pA的虛表,兩個(gè)虛函數(shù)以聲明順序排列。pA指向?qū)ο?pA,則*(int*)pA指向此虛擬表,則(Fun)*((int*)(*(int*)pA))指向FunA,同理,(Fun)*((int*)(*(int*)pA) + 1)指向FunA2。所以,出現(xiàn)了前兩個(gè)結(jié)果。
根據(jù)后兩個(gè)結(jié)果, 我們可以推測(cè)*pC的虛表如下圖所示:
      
也就是說(shuō),由于C中的FunA重寫(override)了A中的FunA,虛擬表中虛擬函數(shù)的地址也被重寫了。
就是這樣,這就是多態(tài)實(shí)現(xiàn)的內(nèi)部機(jī)制。
我們?cè)倩氐阶畛醯膯?wèn)題:為什么*pB出了問(wèn)題。
根據(jù)上邊的結(jié)論,我們大膽地進(jìn)行猜測(cè):由于C是由A、B派生而來(lái),所以objC有兩個(gè)虛擬表,而由于表的順序,pA、pC都指向了對(duì)應(yīng)于A的虛擬表,而pB則指向了對(duì)應(yīng)于B的虛擬表。做個(gè)實(shí)驗(yàn)來(lái)驗(yàn)證我們的猜想是否正確:
我們不改變A、B、C類,將問(wèn)題中的main改一下:
int _tmain(int argc, _TCHAR* argv[]) 
{ 
  C objC; 
  A *pA = &objA; 
  B *pB = &objC; 
  C *pC = &objC; 
   
  typedef void (*Fun)(void); 
 
  Fun fun = (Fun)*((int*)(*(int*)pC)); 
  fun();//第一個(gè)表第一個(gè)函數(shù) 
  fun = (Fun)*((int*)(*(int*)pC)+1); 
  fun();//第一個(gè)表第二個(gè)函數(shù) 
  fun = (Fun)*((int*)(*((int*)pC+1))); 
  fun();<span style="white-space:pre"> </span>//第二個(gè)表第一個(gè)函數(shù) 
  fun = (Fun)*((int*)(*(int*)pB)); 
  fun();//pB指向的表的第一個(gè)函數(shù) 
  return 0; 
}

哈哈,和我們的猜測(cè)完全一致:

FunA1C
FunA2
FunB
FunB
我們可以畫出這樣的虛函數(shù)圖:
        
暫且這樣理解,編譯器執(zhí)行B *pB = &objC時(shí)不是僅僅是賦值,而是做了相應(yīng)的優(yōu)化,將pB指向了第二張?zhí)摫怼?/span>
說(shuō)了這么多,我是只是簡(jiǎn)單地解釋了虛函數(shù)的實(shí)現(xiàn)原理,可究竟對(duì)象的內(nèi)部的內(nèi)存布局是怎樣的?類數(shù)據(jù)成員與多個(gè)虛表的具體內(nèi)存布局又是怎樣的?編譯器是如何在賦值的時(shí)候作了優(yōu)化的呢?我在以后的時(shí)間里會(huì)講一下。

以上就是小編為大家?guī)?lái)的C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法全部?jī)?nèi)容了,希望大家多多支持我們~

上一篇:淺談c++ stl迭代器失效的問(wèn)題

欄    目:C語(yǔ)言

下一篇:C++ 簡(jiǎn)單的任務(wù)隊(duì)列詳解

本文標(biāo)題:C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法

本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/1926.html

網(wǎng)頁(yè)制作CMS教程網(wǎng)絡(luò)編程軟件編程腳本語(yǔ)言數(shù)據(jù)庫(kù)服務(wù)器

如果侵犯了您的權(quán)利,請(qǐng)與我們聯(lián)系,我們將在24小時(shí)內(nèi)進(jìn)行處理、任何非本站因素導(dǎo)致的法律后果,本站均不負(fù)任何責(zé)任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權(quán)所有