Ⅰ C++緙栫▼涓澶氭佹х殑瀹炵幇鏈哄埗鍒板簳鏄浠涔堝憖錛
鈥滀竴涓瀵瑰栨帴鍙o紝澶氫釜鍐呭湪瀹炵幇鈥
琛ュ厖錛氱紪紼嬫槸緙栧啓紼嬪簭鐨勪腑鏂囩畝縐幫紝灝辨槸璁╄$畻鏈轟負瑙e喅鏌愪釜闂棰樿屼嬌鐢ㄦ煇縐嶇▼搴忚捐¤璦緙栧啓紼嬪簭浠g爜錛屽苟鏈緇堝緱鍒扮浉搴旂粨鏋滅殑榪囩▼銆
涓轟簡浣胯$畻鏈鴻兘澶熺悊瑙d漢鐨勬剰鍥撅紝浜虹被灝卞繀欏昏佸皢闇瑙e喅鐨勯棶棰樼殑鎬濊礬銆佹柟娉曘佸拰鎵嬫豹鐭ヨ繜孌甸氳繃璁$畻鏈鴻兘澶熺悊瑙g殑褰㈠紡鍛婅瘔璁$畻鏈猴紝浣垮緱璁$畻鏈鴻兘澶熸牴鎹浜虹殑鎸囦護涓姝ヤ竴姝ュ幓宸ヤ綔錛屽畬鎴愭煇縐嶇壒瀹氬洶鏉庣殑浠誨姟銆傝繖縐嶄漢鍜岃$畻鏈轟箣闂翠氦嫻佺殑榪囩▼灝辯寷絀楁槸緙栫▼銆
緙栫▼錛氳捐″叿澶囬昏緫嫻佸姩浣滅敤鐨勪竴縐嶁滃彲鎺т綋緋燴濄愭敞錛氱紪紼嬩笉涓瀹氭槸閽堝硅$畻鏈虹▼搴忚岃█鐨勶紝閽堝瑰叿澶囬昏緫璁$畻鍔涚殑浣撶郴錛岄兘鍙浠ョ畻緙栫▼銆
渚嬪瓙錛氣憼姣斿傜紪鍐欎竴孌典唬鐮佺▼搴忊憽緙栧啓涓涓鎺у埗璁懼囦綋緋匯
Ⅱ 什麼叫做多態性 在C++中是如何實現多態的
C++中的多態(雖然多態不是C++所特有的,但是C++中的多態確實是很特殊的)分為靜多態和動多態(也就是靜態綁定和動態綁定兩種現象),靜動的區別主要在於這種綁定發生在編譯期還是運行期,發生在編譯期的是靜態綁定,也就是靜多態;發生在運行期的則是動態綁定,也就是動多態。
靜多態可以通過模板和函數重載來實現(之所說C++中的多態主要還是因為模板這個東西),下面舉兩個例子:
1)函數模板
template <typename T>
T max(const T& lsh, const T& rhs)
{
return (lsh > rhs) ? lsh : rhs;
}
返回兩個任意類型對象的最大值(對象),前提是該類型能夠使用>運算符進行比較,並且返回值是bool類型。
使用:
int a = 3; int b = 4;
cout << max(a, b) << endl;
float c = 2.4; float d = 1.2;
cout << max(c, d) << endl;
輸出結果為:
4
2.4
這種綁定發生在編譯期,這是由於模板的實例化是發生在編譯期的,即在編譯時編譯器發現你調用max(a, b)時就自動生成一個函數
int max(const int& lsh, const int& rhs)
{
return (lsh > rhs) ? lsh : rhs;
}
即將所有的T替換成int;
當你調用max(c, d)時就自動生成一個函數
float max(const float& lsh, const float& rhs)
{
return (lsh > rhs) ? lsh : rhs;
}
之所以說開始的函數定義是函數模板,就是因為他就像個模子似的,你可以用鋁作為原料也可以用石膏或者銅。
2)函數重載:
int max (int a, int b)
{
return (a > b) ? a : b;
}
int max (int a, int b, int c)
{
return max(max(a, b), c);
}
兩個函數名稱一樣,參數類型或個數不完全相同,返回值一樣(這個不重要)。
使用:
int a = 3, b = 4, c = 5;
cout << max(a, b) << endl;
cout << max(a, b, c) << endl;
輸出結果為:
4
5
確定函數的過程也發生在編譯器,當你使用max(a, b),編譯器發現只有兩個參數,那麼就調用只有兩個參數的函數版本,當使用max(a, b, c)時,編譯器則使用有3個參數的版本。
通過上面的兩個例子,你還可以使用更為方便的模板函數重載:
template <typename T>
T max(const T& lsh, const T& rhs)
{
return (lsh > rhs) ? lsh : rhs;
}
template <typename T>
T max(const T& a, const T& b, const T& c)
{
return max(max(a, b), c);
}
使用
float a = 3.6, b = 1.2, c = 7.8;
cout << max(a, b, c) << endl;
輸出:
7.8
通過參數個數和類型,編譯器自動生成和調用對應得函數版本!
動多態則是通過繼承、虛函數(virtual)、指針來實現。
class A {
public:
virtual void func() const {
coust << 「A::func()」 << endl;
}
}
class B : public A {
public:
virtual void func() const {
coust << 「B::func()」 << endl;
}
}
使用:
A a* = B();
a->func();
輸出:
B::func()
編譯期是不調用任何函數的,編譯器編譯到a->func()時只是檢查有沒有語法問題,經過檢查沒有。編譯器並不知道調用的是A版本的func()還是B版本的func(),由於a是一個指向B對象的指針,所以a只知道它指向的是一個A類型(或者能轉換成A類型)的對象。通常集成體系就說明了(由於是公有繼承)B是一種A。在運行期,a要調用a所指向對象的func()函數,就對它指向的對象下達調用func()的命令,結果a所指向的是一個B對象,這個對象就調用了自己版本(B版)的func()函數,所以輸出時B::func()
總結:
在編譯期決定你應該調用哪個函數的行為是靜態綁定(static-binding),這種現象就是靜多態。
在運行期決定應該調用哪中類型對象的函數的行為是動態綁定(dynamic-binding),這種現象就是動多態!
註:由於這是我花了有限的時間總結的,語言應用能力比較差,還有比如類模板(靜多態和動多態組合的情況)都沒有說,最近比較忙,請見諒!
如果還不是很懂,我建議你看C++Primer 4th Edition,講的比較清晰,但是比較零散!
Ⅲ 1. 編譯時的多態性與運行時的多態性有什麼區別,他們的實現方法有什麼不同
多態從實現的角度可以劃為兩類:編譯時多態和運行時多態。
編譯時的多態性:就是在程序編譯的時候,也就是生成解決方案的時候就決定要實現什麼操作。
運行時的多態性:就是指直到系統運行時,才根據實際情況決定實現何種操作。
1、多態實現形式不同:
編譯時的多態是通過靜態連編來實現的;運行時的多態是用動態連編來實現的。
2、多態性通過方式不同:
編譯時的多態性主要是通過函數重載和運算符重載來實現的;運行時的多態性主要是通過虛函數來實現的。
(3)什麼實現編譯時的多態性擴展閱讀:
靜態多態性又稱編譯時的多態性。靜態多態性的函數調用速度快、效率高但缺乏靈活性,在程序運行前就應決定執行的函數和方法。
動態多態性的特點是:不在編譯時確定調用的是哪個函數,而是在程序運行過程中才動態地確定操作所針對的對象。又稱運行時的多態性。動態多態性是通過虛函數(virtual function)實現的。
Ⅳ c++涓鐨勮櫄鍑芥暟鏈変粈涔堜綔鐢錛
綾葷殑涓変釜閲嶈佺壒寰侊細灝佽呫佺戶鎵褲佸氭佹с
鍏朵腑澶氭佹у氨鏄閫氳繃鍑芥暟閲嶈澆錛堣繍綆楃﹂噸杞藉疄璐ㄤ笂涔熸槸鍑芥暟閲嶈澆錛夊拰鉶氬嚱鏁版潵瀹炵幇鐨勩
鉶氬嚱鏁扮殑浣滅敤錛氬湪鍩虹被鐢╲irtual澹版槑鎴愬憳鍑芥暟涓鴻櫄鍑芥暟錛屽湪媧劇敓綾諱腑閲嶆柊瀹氬瓭鍦嗗苟涔夎ュ嚱鏁幫紝灝卞彲浠ラ氳繃鍩虹被鎸囬拡鎴栧紩鐢ㄦ潵璁塊棶鍩虹被鍜屾淳鐢熺被涓鐨勫悓鍚嶅嚱鏁般
鉶氬嚱鏁板疄鐜板氭佹э細鍚屼竴綾繪棌涓涓嶅悓綾葷殑瀵硅薄錛屽瑰悓涓鍑芥暟璋冪敤鍋氬嚭涓嶅悓鐨勫搷搴斻
澶氭佹у叾瀹炲氨鏄涓涓鎺ュ彛錛屽氱嶆柟娉曪紝鍒嗕負闈欐佸氭佹у拰鍔ㄦ佸氭佹э紝鍑芥暟閲嶈澆灞炰簬闈欒厰闂規佸氭佹э紝鍦ㄧ▼搴忕紪璇戞椂灝卞彲紜瀹氳皟鐢ㄥ摢涓鍑芥暟錛屽叾榪囩▼縐頒負闈欐佸叧鑱旀垨鏃╂湡鍏寵仈錛岄潤鎬佸氬閥榪規佹у張縐扮紪璇戞椂澶氭佹э紱鉶氬嚱鏁板睘浜庡姩鎬佸氭佹э紝鍦ㄧ▼搴忚繍琛岃繃紼嬩腑鎵嶅姩鎬佸湴紜瀹氭墍璋冪敤鐨勬槸閭d釜瀵硅薄鐨勫嚱鏁幫紝鍏惰繃紼嬬О涓哄姩鎬佸叧鑱旀垨婊炲悗鍏寵仈錛屽姩鎬佸氭佹у張縐拌繍琛屾椂澶氭佹с
Ⅳ C++支持的兩種多態性分別是什麼
靜態聯編支持的多態性稱為編譯時的多態性,也稱靜態多態性,它是通過函數重載和運算符重載實現的。
動態聯編支持的多態性稱為運行時的多態性,也稱動態多態性,它是通過繼承和虛函數實現的。
Ⅵ C++中多態是怎樣實現的
多態是一種不同的對象以單獨的方式作用於相同消息的能力,這個概念是從自然語言中引進的。例如,動詞「關閉」應用到不同的事務上其意思是不同的。關門,關閉銀行賬號或關閉一個程序的窗口都是不同的行為;其實際的意義取決於該動作所作用的對象。 大多數面向對象語言的多態特性都僅以虛擬函數的形式來實現,但C++除了一般的虛擬函數形式之外,還多了兩種靜態的(即編譯時的)多態機制: 2、模板:例如,當接受到相同的消息時,整型vector對象和串vector對象對消息反映是不同的,我們以關閉行為為例: vector < int > vi; vector < string > names; string name("VC知識庫"); vi.push_back( 5 ); // 在 vector 尾部添加整型 names.push_back (name); // 添加串和添加整型體現差別的潛在的操作 靜態的多態機制不會導致與虛擬函數相關的運行時開。此外,操作符重載和模板兩者是通用演算法最基本的東西,在STL中體現得尤為突出。 那麼接下來我們說說以虛函數形式多態: 通常都有以重載、覆蓋、隱藏來三中方式,三種方式的區別大家應該要很深入的了解,這里就不多說了。 許多開發人員往往將這種情況和C++的多態性搞混淆,下面我從兩方面為大家解說: 1、 編譯的角度 C++編譯器在編譯的時候,要確定每個對象調用的函數的地址,這稱為早期綁定(early binding)。2、 內存模型的角度為了確定對象調用的函數的地址,就要使用遲綁定(late binding)技術。當編譯器使用遲綁定時,就會在運行時再去確定對象的類型以及正確的調用函數。而要讓編譯器採用遲綁定,就要在基類中聲明函數時使用virtual關鍵字(注意,這是必須的,很多開發人員就是因為沒有使用虛函數而寫出很多錯誤的例子),這樣的函數我們稱為虛函數。一旦某個函數在基類中聲明為virtual,那麼在所有的派生類中該函數都是virtual,而不需要再顯式地聲明為virtual。 那麼如何定位虛表呢?編譯器另外還為每個類的對象提供了一個虛表指針(即vptr),這個指針指向了對象所屬類的虛表。在程序運行時,根據對象的類型去初始化vptr,從而讓vptr正確的指向所屬類的虛表,從而在調用虛函數時,就能夠找到正確的函數。 正是由於每個對象調用的虛函數都是通過虛表指針來索引的,也就決定了虛表指針的正確初始化是非常重要的。換句話說,在虛表指針沒有正確初始化之前,我們不能夠去調用虛函數。那麼虛表指針在什麼時候,或者說在什麼地方初始化呢? 答案是在構造函數中進行虛表的創建和虛表指針的初始化。還記得構造函數的調用順序嗎,在構造子類對象時,要先調用父類的構造函數,此時編譯器只「看到了」父類,並不知道後面是否後還有繼承者,它初始化父類對象的虛表指針,該虛表指針指向父類的虛表。當執行子類的構造函數時,子類對象的虛表指針被初始化,指向自身的虛表。 要注意:對於虛函數調用來說,每一個對象內部都有一個虛表指針,該虛表指針被初始化為本類的虛表。所以在程序中,不管你的對象類型如何轉換,但該對象內部的虛表指針是固定的,所以呢,才能實現動態的對象函數調用,這就是C++多態性實現的原理。總結(基類有虛函數):1、 每一個類都有虛表。2、虛表可以繼承,如果子類沒有重寫虛函數,那麼子類虛表中仍然會有該函數的地址,只不過這個地址指向的是基類的虛函數實現。如果基類3個虛函數,那麼基類的虛表中就有三項(虛函數地址),派生類也會有虛表,至少有三項,如果重寫了相應的虛函數,那麼虛表中的地址就會改變,指向自身的虛函數實現。如果派生類有自己的虛函數,那麼虛表中就會添加該項。3、派生類的虛表中虛函數地址的排列順序和基類的虛表中虛函數地址排列順序相同。
Ⅶ 編譯時的多態性和運行時的多態性在實現方法上有何不同
我不知道你哪本書上看到的,但是,只要不是後綁定就不能稱為多態,前綁定只能稱為代碼重用,比如函數的重載、覆蓋以及一般的類繼承。
多態的關鍵特點就是:在運行時虛基類指針指向派生類對象地址,而將派生類對象地址賦值給基類指針,這就是所謂的後綁定,編譯時綁定稱為前綁定,因此多態另一個特點就是「動態「。換句話說,如果是後綁定,編譯器事先是不知道在運行時指針將指向哪一種派生類的對象,因此基類指針必須是「虛「的,虛基類中不能有任何實現只有定義,此時虛基類的作用就是一個類介面,這樣才能在編譯時「模糊」掉類型匹配原則,基類的作用只是個約定,定義了函數調用格式,而只在運行時才確定指針具體指向哪一個對象。
而所謂編譯時的多態性根本不存在,如果編譯器能確定基類指針指向哪一個派生類對象地址,就不是多態,哪怕你採用重載覆蓋或者繼承,這些編譯器已經可以預知的事情,一旦編譯完成就固定了,運行時無法更改的,比如你不能在不重新編譯的情況下增加一個重載,這就制約了程序運行時的靈活性以及可擴充性。而多態完全可以實現「熱「更新,更多的是便於程序的可擴充性。你完全可以將派生類編譯在DLL中,每當更新程序時,只要替換掉DLL而不用重新編譯全部代碼。
Ⅷ 編譯時多態性使用什麼獲得!A重載函數B繼承C虛函數D.B和C
函數重載和模板。就這題來說選A。
繼承和虛函數對應的多態需要在運行的時候才能確定具體對象,所以不屬於編譯時多態。
函數重載是讓一個函數名對應多個函數,編譯器會根據調用時候的特徵確定要調用的函數,不需要再運行時處理。
而模板是讓一個一個類型模板或者函數模板對應多個類型或者函數,編譯器根據對模板實例化是使用的參數生成具體的類和函數,也不是在運行時進行的。
另外注意模板變數不屬於多態范疇。