C++中的多態與虛函數的外部完成辦法。本站提示廣大學習愛好者:(C++中的多態與虛函數的外部完成辦法)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中的多態與虛函數的外部完成辦法正文
1、什麼是多態
多態性可以復雜概括為“一個接口,多種行為”。
也就是說,向不同的對象發送同一個音訊, 不同的對象在接納時會發生不同的行為(即辦法)。也就是說,每個對象可以用自己的方式去呼應共同的音訊。所謂音訊,就是調用函數,不同的行為就是指不同的完成,即執行不同的函數。這是一種泛型技術,即用相反的代碼完成不同的舉措。這表現了面向對象編程的優越性。
多態分為兩種:
(1)編譯時多態:次要經過函數的重載和模板來完成。
(2)運轉時多態:次要經過虛函數來完成。
2、幾個相關概念
(1)掩蓋、重寫(override)
override指基類的某個成員函數為虛函數,派生類又定義一成員函數,除函數體的其他局部都與基類的成員函數相反。留意,假如只是函數名相反,形參或前往類型不同的話,就不能稱為override,而是hide。
(2)重載(overload)
指同一個作用域出生多個函數名相反,但是形參不同的函數。編譯器在編譯的時分,經過實參的個數和類型,選擇最終調用的函數。
(3)隱藏(hide)
分為兩種:
1)部分變量或許函數隱藏了全局變量或許函數
2)派生類擁有和基類同名的成員函數或成員變量。
發生的後果:使全局或基類的變量、函數不可見。
3、幾個復雜的例子
/****************************************************************************************************** * File:PolymorphismTest * Introduction:測試多態的一些特性。 * 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函數並不是虛函數,所以是隱藏,而不是重寫 { 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。由於p是基類指針,p->foo指向一個具有固定偏移量的函數。也就是基類函數 p->fun(); //輸入4。多態。雖然p是基類指針,但實踐上指向的是一個子類對象。p->fun指向的是一個虛函數。依照靜態類型,調用子類函數 return 0; }
4、運轉時多態以及虛函數的外部完成
看了上邊幾個復雜的例子,我豁然開朗,原來這就是多態,這麼復雜,明白啦!
好,那我們再看一個例子:
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; }
運轉後果:
5241376 1563032
5241376 1563032
5241380 1563256
5241376 1563032
細心的同志一定發現了pB出了問題,為什麼明明都是指向objC的指針,pB跟他人的值都不一樣呢?
是不是編譯器出了問題呢?
當然不是!我們先講結論:
(1)每一個含有虛函數的類,都會生成虛表(virtual table)。這個表,記載了對象的靜態類型,決議了執行此對象的虛成員函數的時分,真正執行的那一個成員函數。
(2)關於有多個基類的類對象,會有多個虛表,每一個基類對應一個虛表,同時,虛表的順序和承繼時的順序相反。
(3)在每一個類對象所占用的內存中,虛指針位於最前邊,每個虛指針指向對應的虛表。
先從復雜的單個基類說起:
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指向的第一個函數 fun = (Fun)*((int*)(*(int*)pA) +1); fun();//pA指向的第二個函數 fun = (Fun)*((int*)(*(int*)pC)); fun();//pC指向的第一個函數 fun = (Fun)*((int*)(*(int*)pC) + 1); fun();//pC指向的第二個函數 return 0; }
運轉後果:
FunA1int _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();//第一個表第一個函數 fun = (Fun)*((int*)(*(int*)pC)+1); fun();//第一個表第二個函數 fun = (Fun)*((int*)(*((int*)pC+1))); fun();<span > </span>//第二個表第一個函數 fun = (Fun)*((int*)(*(int*)pB)); fun();//pB指向的表的第一個函數 return 0; }
哈哈,和我們的猜想完全分歧:
FunA1C以上就是為大家帶來的C++中的多態與虛函數的外部完成辦法全部內容了,希望大家多多支持~