C++中的虛擬繼承
1.為什麼要引入虛擬繼承
虛擬繼承是多重繼承中特有的概念。虛擬基類是為解決多重繼承而出現的。如:類D繼承自類B1、B2,而類B1、B2都繼承自類A,因此在類D中兩次出現類A中的變數和函式。為了節省記憶體空間,可以將B1、B2對A的繼承定義為虛擬繼承,而A就成了虛擬基類。實現的程式碼如下:
class A
class B1:public virtual A;
class B2:public virtual A;
class D:public B1,public B2;
虛擬繼承在一般的應用中很少用到,所以也往往被忽視,這也主要是因為在C++中,多重繼承是不推薦的,也並不常用,而一旦離開了多重繼承,虛擬繼承就完全失去了存在的必要因為這樣只會降低效率和佔用更多的空間。
2.引入虛繼承和直接繼承會有什麼區別呢
由於有了間接性和共享性兩個特徵,所以決定了虛繼承體系下的物件在訪問時必然會在時間和空間上與一般情況有較大不同。
2.1時間:在通過繼承類物件訪問虛基類物件中的成員(包括資料成員和函式成員)時,都必須通過某種間接引用來完成,這樣會增加引用定址時間(就和虛擬函式一樣),其實就是調整this指標以指向虛基類物件,只不過這個調整是執行時間接完成的。
2.2空間:由於共享所以不必要在物件記憶體中儲存多份虛基類子物件的拷貝,這樣較之多繼承節省空間。虛擬繼承與普通繼承不同的是,虛擬繼承可以防止出現diamond繼承時,一個派生類中同時出現了兩個基類的子物件。也就是說,為了保證這一點,在虛擬繼承情況下,基類子物件的佈局是不同於普通繼承的。因此,它需要多出一個指向基類子物件的指標。
3.筆試,面試中常考的C++虛擬繼承的知識點
第一種情況: 第二種情況: 第三種情況 第四種情況:
class a class a class a class a
{ { { {
virtual void func(); virtual void func(); virtual void func(); virtual void func();
}; }; char x; char x;
class b:public virtuala class b :public a }; };
{ { class b:public virtual a class b:public a
virtual void foo(); virtual void foo(); { {
}; }; virtual void foo(); virtual void foo();
}; };
如果對這四種情況分別求sizeof(a), sizeof(b)。結果是什麼樣的呢?下面是輸出結果:(在vc6.0中執行)
第一種:4,12
第二種:4,4
第三種:8,16
第四種:8,8
想想這是為什麼呢?
因為每個存在虛擬函式的類都要有一個4位元組的指標指向自己的虛擬函式表,所以每種情況的類a所佔的位元組數應該是沒有什麼問題的,那麼類b的位元組數怎麼算呢?看“第一種”和“第三種”情況採用的是虛繼承,那麼這時候就要有這樣的一個指標vptr_b_a,這個指標叫虛類指標,也是四個位元組;還要包括類a的位元組數,所以類b的位元組數就求出來了。而“第二種”和“第四種”情況則不包括vptr_b_a這個指標,這回應該木有問題了吧。
4.c++過載、覆蓋、隱藏的區別和執行方式
既然說到了繼承的問題,那麼不妨討論一下經常提到的過載,覆蓋和隱藏
4.1成員函式被過載的特徵
(1)相同的範圍(在同一個類中);
(2)函式名字相同;
(3)引數不同;
(4)virtual 關鍵字可有可無。
4.2“覆蓋”是指派生類函式覆蓋基類函式,特徵是:
(1)不同的範圍(分別位於派生類與基類);
(2)函式名字相同;
(3)引數相同;
(4)基類函式必須有virtual 關鍵字。
4.3“隱藏”是指派生類的函式遮蔽了與其同名的基類函式,特徵是:
(1)如果派生類的函式與基類的函式同名,但是引數不同,此時,不論有無virtual關鍵字,基類的函式將被隱藏(注意別與過載混淆)。
(2)如果派生類的函式與基類的函式同名,但是引數相同,但是基類函式沒有virtual 關鍵字。此時,基類的函式被隱藏(注意別與覆蓋混淆)。
小結:說白了就是如果派生類和基類的函式名和引數都相同,屬於覆蓋,這是可以理解的吧,完全一樣當然要覆蓋了;如果只是函式名相同,引數並不相同,則屬於隱藏。
4.4 三種情況怎麼執行:
4.4.1 過載:看引數。
4.4.2 隱藏:用什麼就呼叫什麼。
4.4.3 覆蓋:呼叫派生類。
原文章連結:
http://www.cnblogs.com/BeyondAnyTime/archive/2012/06/05/2537451.html
相關推薦
C++ 中 虛擬繼承 的概念
C++中虛擬繼承的概念 為了解決從不同途徑繼承來的同名的資料成員在記憶體中有不同的拷貝造成資料不一致問題,將共同基類設定為虛基類。這時從不同的路徑繼承過來的同名數據成員在記憶體中就只有一個拷貝,同一個函式名也只有一個對映。這樣不僅就解決了二義性問題,也節省了記憶體,避免了資
C++中虛擬函式工作原理和 虛 繼承類的記憶體佔用大小計算
虛擬函式的實現要求物件攜帶額外的資訊,這些資訊用於在執行時確定該物件應該呼叫哪一個虛擬函式。典型情況下,這一資訊具有一種被稱為 vptr(virtual table pointer,虛擬函式表指標)的指標的形式。vptr 指向一個被稱為 vtbl(virtual t
C++中單繼承與多重繼承下的虛擬函式表
轉自:http://www.cnblogs.com/Z465360621/articles/4561344.html 虛擬函式表,以及虛擬函式指標: 1)每個有虛擬函式的類都有自己的虛擬函式表,每個包含虛擬函式的類物件都有虛擬函式表指標。 2)對於多重繼承
C#中的繼承與覆蓋
sta 文章 class static color read con public ner 原文發布時間為:2009-03-03 —— 來源於本人的百度文章 [由搬家工具導入]//using System;//using System.Collections.Generic
C++中的繼承詳解
C++ 繼承 [TOC] 繼承基本知識 定義: 繼承是面向對復用的重要手段。通過繼承定義一個類,繼承是類型之間的關系建模,共享公有的東西,實現各自本質不同的東西。 繼承關系: 三種繼承關系下基類成員的在派生類的訪問關系變化(圖) 舉個栗子(公有繼承) ```c+
關於C++中的繼承和過載的區別
C++中的很多特性光從概念上的話,很難做區分。或者說,概念讓人容易模糊,比如說函式過載和函式繼承。 先說過載,過載分為操作符過載和函式名過載,其中,操作符過載就是對運算操作符的原有功能進
c++中虛擬函式的理解
虛擬函式的作用,事實上就是實現了多型性,就是實現以共同的方法,但因個體差異而採用不同的策略。下面有程式碼例項來描述: class A{ public: void print(){ cout<<”This is A”<<endl;} }; class B:publ
C++中虛擬函式與函式
解構函式為什麼要宣告為虛 函式??? 基類的解構函式需要宣告為虛擬函式: 當派生類物件經由一個基類指標被刪除,而該基類帶著一個non-virtual解構函式,實際執行時通常發生的是物件的派生類成員沒有被銷燬。這也就是區域性銷燬,會發生記憶體洩漏,所以我們通常將基類的解構函式需要宣告為
C++中的繼承和組合區別使用
C++的“繼承”特性可以提高程式的可複用性。正因為“繼承”太有用、太容易用,才要防止亂用“繼承”。我們要給“繼承”立一些使用規則: 一、如果類A 和類B 毫不相關,不可以為了使B 的功能更多些而讓B 繼承A 的功能。 不要覺得“
C++中虛擬函式工作原理
C++中的虛擬函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父類型別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。 所謂泛型技術,比如:模板技術,RTTI技術,虛擬函式技術,要麼是試圖做到在編譯時決議,要麼試圖做到執行時決議。 虛擬函式表(
原來Java中的繼承和C#中的繼承是不一樣的
因為之前在學校裡學的是Java,C#是自學的,一直感覺Java和C#就像是孿生兄弟,不過今天才發現原來Java中的繼承和C#中的繼承還是有點不一樣的 在Java中子類繼承父類的方法,如果在子類重新定義了父類方法的實現,那麼這個過程就是重寫,且只能是重寫,而在C
C++中三大繼承方式的執行效果
#include <iostream> using namespace std; class A { public: void inial(){}; int size; protected: int val; private: int pr
c++中虛擬函式和純虛擬函式定義
只有用virtual宣告類的成員函式,使之成為虛擬函式,不能將類外的普通函式宣告為虛擬函式。因為虛擬函式的作用是允許在派生類中對基類的虛擬函式重新定義。所以虛擬函式只能用於類的繼承層次結構中。 一個成員函式被宣告為虛擬函式後,在同一類族中的類就不能
關於c++中虛擬函式和介面的關係區分(簡單)
虛擬函式: 虛擬函式的作用是實現動態聯編,也就是在程式的執行階段動態地選擇合適的成員函式,在定義了虛擬函式後,可以在基類的派生類中對虛擬函式重新定義,在派生類中重新定義的函式應與虛擬函式具有相同的形參個數和形參型別。以實現統一的介面,不同定義
C++中多繼承建構函式呼叫順序
class B1 {public: B1(int i) {cout<<"consB1"<<i<<endl;} };//定義基類B1 class B2 {public: B2(int j) {cout<<"consB2"<<
C++中虛擬函式表儲存位置淺析
關於C++中虛擬函式表,我們知道這樣一些事實: 1. 當class中存在virtual函式時,編譯器會為這個class追加一個void** __vfptr資料成員。 2. C++程式執行時,實際函式的呼叫,是通過查詢__vfptr來獲取的,從而實現多型。 3. 多型的實現,
C#中的繼承和多型
繼承的作用: 繼承可以減少程式碼的冗餘,提高程式碼的複用性。 是面向物件程式設計的組成部分,是所有面向物件的語言都要具備的特性。 繼承的實現: 先將幾個類中相同的屬性和方法進行抽離,單獨定義在一個新建的類中。 其他的類直接繼承當前新建的
淺析C++中虛擬函式的呼叫及物件的內部佈局
在我那篇《淺析C++中的this指標》中,我通過分析C++程式碼編譯後生成的彙編程式碼來分析this指標的實現方法。這次我依然用分析C++程式碼編譯後生成的彙編程式碼來說明C++中虛擬函式呼叫的實現方法,順便也說明一下C++中的物件內部佈局。下面所有的彙編程式碼都是
C++中的繼承特性(1)
1.何為繼承 首先,繼承是什麼?繼承可以簡單理解為孩子繼承了父母雙親的基因,在擁有父母某些特性的同時,又有自己獨立的特性。 在C++中,繼承是類與類之間的繼承,即某個類可以繼承它類的成員變數、成員函
C++中虛擬函式的作用是什麼?它應該怎麼用呢?
虛擬函式聯絡到多型,多型聯絡到繼承。所以本文中都是在繼承層次上做文章。沒了繼承,什麼都沒得談。下面是對C++的虛擬函式這玩意兒的理解。 一, 什麼是虛擬函式 (如果不知道虛擬函式為何物,但有急切的想知道,那你就應該從這裡開始)簡單地說,那些被virtual關鍵字修飾的成員