C++虛繼承的概念

轉載:http://blog.csdn.net/crystal_avast/article/details/7678704

C++中虛擬繼承的概念

為了解決從不同途徑繼承來的同名的數據成員在內存中有不同的拷貝造成數據不一致問題,將共同基類設置為虛基類。這時從不同的路徑繼承過來的同名數據成員在內存中就只有一個拷貝,同一個函數名也只有一個映射。這樣不僅就解決了二義性問題,也節省了內存,避免了數據不一致的問題。
class 派生類名:virtual 繼承方式? 基類名
virtual是關鍵字,聲明該基類為派生類的虛基類。
在多繼承情況下,虛基類關鍵字的作用范圍和繼承方式關鍵字相同,只對緊跟其后的基類起作用。
聲明了虛基類之后,虛基類在進一步派生過程中始終和派生類一起,維護同一個基類子對象的拷貝。

?

C++虛擬繼承

◇概念:

C++使用虛擬繼承(Virtual Inheritance),解決從不同途徑繼承來的同名的數據成員在內存中有不同的拷貝造成數據不一致問題,將共同基類設置為虛基類。這時從不同的路徑繼承過來的同名數據成員在內存中就只有一個拷貝,同一個函數名也只有一個映射。

?

◇解決問題:

解決了二義性問題,也節省了內存,避免了數據不一致的問題。
?
◇同義詞: 
虛基類(把一個動詞當成一個名詞而已)
當在多條繼承路徑上有一個公共的基類,在這些路徑中的某幾條匯合處,這個公共的基類就會產生多個實例(或多個副本),若只想保存這個基類的一個實例,可以將這個公共基類說明為虛基類。

?

◇語法:

class 派生類: virtual 基類1,virtual 基類2,...,virtual 基類n

{

...//派生類成員聲明

};

?

◇執行順序

首先執行虛基類的構造函數,多個虛基類的構造函數按照被繼承的順序構造;

執行基類的構造函數,多個基類的構造函數按照被繼承的順序構造;

執行成員對象的構造函數,多個成員對象的構造函數按照申明的順序構造;

執行派生類自己的構造函數;

析構以與構造相反的順序執行;

mark

從虛基類直接或間接派生的派生類中的構造函數的成員初始化列表中都要列出對虛基類構造函數的調用。但只有用于建立對象的最派生類的構造函數調用虛基類的構造函數,而該派生類的所有基類中列出的對虛基類的構造函數的調用在執行中被忽略,從而保證對虛基類子對象只初始化一次。

在一個成員初始化列表中同時出現對虛基類和非虛基類構造函數的調用時,虛基類的構造函數先于非虛基類的構造函數執行。

?

◇因果:

多重繼承->二義性->虛擬繼承解決

?

◇二義性:

? 1:?//-----------------------------------------------------

 2: //名稱:blog_virtual_inherit.cpp 
 3: //說明:C++虛擬繼承學習演示 
 4: //環境:VS2005 
 5: //blog:pppboy.blog.163.com 
 6: //---------------------------------------------------- 
 7: #include "stdafx.h"
 8: #include <iostream>
 9: using namespace std;
 10:
 11: //Base 
 12: class Base
 13: {
 14: public:
 15: Base(){cout << "Base called..."<< endl;}
 16: void print(){cout << "Base print..." <<endl;}
 17: private:
 18: };
 19:
 20: //Sub 
 21: class Sub //定義一個類 Sub 
 22: {
 23: public:
 24: Sub(){cout << "Sub called..." << endl;}
 25: void print(){cout << "Sub print..." << endl;}
 26: private:
 27: };
 28:
 29: //Child 
 30: class Child : public Base , public Sub //定義一個類Child 分別繼承自 Base ,Sub 
 31: {
 32: public:
 33: Child(){cout << "Child called..." << endl;}
 34: private:
 35: };
 36:
 37: int main(int argc, char* argv[])
 38: {
 39: Child c;
 40:
 41: //不能這樣使用,會產生二意性,VC下error C2385 
 42: //c.print();  
 43:
 44: //只能這樣使用 
 45: c.Base::print();
 46: c.Sub::print();
 47:
 48: system("pause");
 49: return 0;
 50: }

?

◇多重繼承:

 
 1: //-----------------------------------------------------  
 2: //名稱:blog_virtual_inherit.cpp  
 
3: //說明:C++虛擬繼承學習演示  
 4: //環境:VS2005  
 5: //blog:pppboy.blog.163.com  
 6: //----------------------------------------------------  
 7: #include "stdafx.h"  
 8: #include <iostream>
 9: using namespace std;  
 10:
 11: int gFlag = 0;  
 12:
 13: class Base  
 14: {
 15: public:  
 16: Base(){cout << "Base called : " << gFlag++ << endl;}  
 17: void print(){cout << "Base print" <<endl;}  
 18: };
 19:
 20: class Mid1 : public Base  
 21: {
 22: public:  
 23: Mid1(){cout << "Mid1 called" << endl;}  
 24: private:  
 25: };
 26:
 27: class Mid2 : public Base  
 28: {
 29: public:  
 30: Mid2(){cout << "Mid2 called" << endl;}  
 31: };
 32:
 33: class Child:public Mid1, public Mid2  
 34: {
 35: public:  
 36: Child(){cout << "Child called" << endl;}  
 37: };
 38:
 39: int main(int argc, char* argv[])  
 40: {
 41: Child d;
 42:
 43: //不能這樣使用,會產生二意性  
     //d.print();  
 45:
 46: //只能這樣使用  
 47: d.Mid1::print();
 48: d.Mid2::print();
 49:
 50: system("pause");  
 51: return 0;  
 52: }
 53:

//output

 
 Base called : 0
 Mid1 called
 Base called : 1 
 Mid2 called
 Child called
 Base print
 Base print

?

◇虛擬繼承

在派生類繼承基類時,加上一個virtual關鍵詞則為虛擬繼承

 
 1: //-----------------------------------------------------  
 2: //名稱:blog_virtual_inherit.cpp  
 
3: //說明:C++虛擬繼承學習演示  
 4: //環境:VS2005  
 5: //blog:pppboy.blog.163.com  
 6: //----------------------------------------------------  
 7: #include "stdafx.h"  
 8: #include <iostream>
 9: using namespace std;  
 10:
 11: int gFlag = 0;  
 12:
 13: class Base  
 14: {
 15: public:  
 16: Base(){cout << "Base called : " << gFlag++ << endl;}  
 17: void print(){cout << "Base print" <<endl;}  
 18: };
 19:
 20: class Mid1 : virtual public Base  
 21: {
 22: public:  
 23: Mid1(){cout << "Mid1 called" << endl;}  
 24: private:  
 25: };
 26:
 27: class Mid2 : virtual public Base  
 28: {
 29: public:  
 30: Mid2(){cout << "Mid2 called" << endl;}  
 31: };
 32:
 33: class Child:public Mid1, public Mid2  
 34: {
 35: public:  
 36: Child(){cout << "Child called" << endl;}  
 37: };
 38:
 39: int main(int argc, char* argv[])  
 40: {
 41: Child d;
 42:
 43: //這里可以這樣使用  
 44: d.print();
 45:
 46: //也可以這樣使用  
 47: d.Mid1::print();
 48: d.Mid2::print();
 49:
 50: system("pause");  
 51: return 0;  
 52: }
 53:

//output

 
 1: Base called : 0
 2: Mid1 called
 3: Mid2 called
 4: Child called
 5: Base print
 6: Base print
 7: Base print
 8: 請按任意鍵繼續. . .

?

◇通過輸出的比較

1.在多繼承情況下,虛基類關鍵字的作用范圍和繼承方式關鍵字相同,只對緊跟其后的基類起作用。
2.聲明了虛基類之后,虛基類在進一步派生過程中始終和派生類一起,維護同一個基類子對象的拷貝。
3.觀察類構造函數的構造順序,拷貝也只有一份。
?
◇與虛函數關系 
虛擬繼承與虛函數有一定相似的地方,但他們之間是絕對沒有任何聯系的。
再想一次:虛擬繼承,虛基類,虛函數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384359.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384359.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384359.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數組名和取數組名的區別

先來個簡單的小案例 #include <stdio.h> #include <iostream>using namespace std;int main() {int a[10] { 0 };printf("%d\n", a);printf("%d\n", &a);printf("%d\n", a1);printf("%d\n", &a1);printf("…

C++繼承詳解三 ----菱形繼承、虛繼承

轉載&#xff1a;http://blog.csdn.net/pg_dog/article/details/70175488 今天呢&#xff0c;我們來講講菱形繼承與虛繼承。這兩者的講解是分不開的&#xff0c;要想深入了解菱形繼承&#xff0c;你是繞不開虛繼承這一點的。它倆有著什么關系呢&#xff1f;值得我們來剖析。 菱…

Linux :IO多路復用模型

轉載&#xff1a;http://blog.csdn.net/mr253727942/article/details/50827127 一、IO多路復用定義 IO多路復用允許應用在多個文件描述符上阻塞&#xff0c;并在某一個可以讀寫時通知&#xff0c; 一般遵循下面的設計原則&#xff1a;、 IO多路復用&#xff1a;任何文件描述符…

leetcode(一)刷題兩數之和

給定一個整數數組 nums 和一個整數目標值 target&#xff0c;請你在該數組中找出 和為目標值 target 的那 兩個 整數&#xff0c;并返回它們的數組下標。 示例 1&#xff1a; 輸入&#xff1a;nums [2,7,11,15], target 9 輸出&#xff1a;[0,1] 解釋&#xff1a;因為 nums[…

Linux并發服務器編程之多線程并發服務器

轉載&#xff1a;http://blog.csdn.net/qq_29227939/article/details/53782198 上一篇文章使用fork函數實現了多進程并發服務器&#xff0c;但是也提到了一些問題&#xff1a; fork是昂貴的。fork時需要復制父進程的所有資源&#xff0c;包括內存映象、描述字等&#xff1b;目…

leetcode(二)二分法查找算法

給定一個 n 個元素有序的&#xff08;升序&#xff09;整型數組 nums 和一個目標值 target &#xff0c;寫一個函數搜索 nums 中的 target&#xff0c;如果目標值存在返回下標&#xff0c;否則返回 -1。 示例 1: 輸入: nums [-1,0,3,5,9,12], target 9 輸出: 4 解釋: 9 出現在…

leetcode(977)有序數組的平方

給你一個按 非遞減順序 排序的整數數組 nums&#xff0c;返回 每個數字的平方 組成的新數組&#xff0c;要求也按 非遞減順序 排序。 示例 1&#xff1a; 輸入&#xff1a;nums [-4,-1,0,3,10] 輸出&#xff1a;[0,1,9,16,100] 解釋&#xff1a;平方后&#xff0c;數組變為 […

IO多路復用之select全面總結(必看篇)

轉載&#xff1a;http://www.jb51.net/article/101057.htm 1、基本概念 IO多路復用是指內核一旦發現進程指定的一個或者多個IO條件準備讀取&#xff0c;它就通知該進程。IO多路復用適用如下場合&#xff1a; &#xff08;1&#xff09;當客戶處理多個描述字時&#xff08;一般…

leetcode(189) 旋轉數組

**給定一個數組&#xff0c;將數組中的元素向右移動 k 個位置&#xff0c;其中 k 是非負數。 進階&#xff1a; 盡可能想出更多的解決方案&#xff0c;至少有三種不同的方法可以解決這個問題。 你可以使用空間復雜度為 O(1) 的 原地 算法解決這個問題嗎&#xff1f; 示例 1: …

I/O 多路復用之select

轉載&#xff1a;http://blog.csdn.net/u012432778/article/details/47347133 概述 Linux提供了三種 I/O 多路復用方案&#xff1a;select&#xff0c;poll和epoll。在這一篇博客里先討論select, poll 在將下一篇中介紹&#xff0c;epoll是Linux特有的高級解決方案&#xff0c;…

leetcode(283)移動零

283. 移動零 給定一個數組 nums&#xff0c;編寫一個函數將所有 0 移動到數組的末尾&#xff0c;同時保持非零元素的相對順序。 示例: 輸入: [0,1,0,3,12] 輸出: [1,3,12,0,0] 說明: 必須在原數組上操作&#xff0c;不能拷貝額外的數組。 盡量減少操作次數。 方法一&#xff1…

exec函數族實例解析

轉載&#xff1a;http://www.cnblogs.com/blankqdb/archive/2012/08/23/2652386.html fork()函數通過系統調用創建一個與原來進程(父進程)幾乎完全相同的進程(子進程是父進程的副本&#xff0c;它將獲得父進程數據空間、堆、棧等資源的副本。注意&#xff0c;子進程持有的是上述…

leetcode(167)兩數之和 II - 輸入有序數組

兩數之和 II - 輸入有序數組 給定一個已按照 升序排列 的整數數組 numbers &#xff0c;請你從數組中找出兩個數滿足相加之和等于目標數 target 。 函數應該以長度為 2 的整數數組的形式返回這兩個數的下標值。numbers 的下標 從 1 開始計數 &#xff0c;所以答案數組應當滿足 …

常量指針與指針常量的區別(轉帖)

轉載&#xff1a;http://www.cnblogs.com/witty/archive/2012/04/06/2435311.html 三個名詞雖然非常繞嘴&#xff0c;不過說的非常準確。用中國話的語義分析就可以很方便地把三個概念區分開。 一) 常量指針。 常量是形容詞&#xff0c;指針是名詞&#xff0c;以指針為中心的一個…

c/c++錯題總結

1.類名 對象名 默認調用“對象名()”這個構造函數&#xff0c;在棧內存中存在對象名&#xff0c;在堆內存中存在實際對象&#xff1b; 2.類名 對象名(一個或以上個參數) 默認調用相應的構造函數&#xff0c;在棧內存中存在對象名&#xff0c;在堆內存中也是存在實際對象的&a…

智能指針學習筆記

轉載&#xff1a;http://www.cnblogs.com/wuchanming/p/4411878.html 1. 介紹 本文介紹智能指針的使用。智能指針是c 中管理資源的一種方式&#xff0c;用智能指針管理資源&#xff0c;不必擔心資源泄露&#xff0c;將c 程序員 從指針和內存管理中解脫出來&#xff0c;再者&…

c++程序編譯過程

c程序編譯分成四個過程&#xff1a;編譯預處理&#xff0c;編譯&#xff0c;匯編&#xff0c;鏈接 編譯預處理&#xff1a;處理以#為開頭 編譯&#xff1a;將.cpp文件翻譯成.s匯編文件 匯編&#xff1a;將.s匯編文件翻譯成機器指令.o文件 鏈接&#xff1a;匯編生產的目標文件.o…

仿函數(函數對象)

轉載&#xff1a;http://www.cnblogs.com/wuchanming/p/4411867.html 本文乃作者學習《C標準程序庫》的學習筆記&#xff0c;首先介紹了仿函數&#xff08;函數對象&#xff09;和函數適配器&#xff08;配接器&#xff09;的概念&#xff0c;然后列出STL中所有的仿函數&#x…

C++ template —— 動多態與靜多態(六)

轉載&#xff1a;http://www.cnblogs.com/yyxt/p/5157517.html 前面的幾篇博文介紹了模板的基礎知識&#xff0c;并且也深入的講解了模板的特性。接下來的博文中&#xff0c;將會針對模板與設計進行相關的介紹。 ------------------------------------------------------------…

變量之間的區別

全局變量、局部變量、靜態全局變量、靜態局部變量的區別 c變量根據定義具有不同的生命周期&#xff0c;會有不同的作用域&#xff0c;主要有六個作用域&#xff1a;全局作用域&#xff0c;局部作用域&#xff0c;文件作用域&#xff0c;類作用域&#xff0c;語句作用域&#xf…