多重繼承之虛繼承(主要是為了解決產生的數據冗余問題)

虛繼承?是面向對象編程中的一種技術,是指一個指定的基類,在繼承體系結構中,將其成員數據實例共享給也從這個基類型直接或間接派生的其它類。形式:在繼承定義中包含了virtual關鍵字的繼承關系,如下圖中,類A就叫做虛基類。
虛擬繼承是多重繼承中的菱形繼承所特有的概念。虛擬基類是為解決多重繼承而出現的。

菱形繼承中既有多繼承,如下圖所示:

菱形繼承中也有多重繼承:

?現實中的例子:



問題來了:在類D的實例中將有兩份類A的變量,這種數據冗余的現象我們不能容忍其存在?這就會需要用到虛繼承!!!廢話不多說直接上代碼,直接粘貼可用。

#include <iostream>

#include <stdlib.h>
#include <string>
using namespace std;


/**
?* 定義人類: Person
?*/
class Person
{
public:
? ? Person(string color = "blue"):m_strColor(color)
{
cout << "Person" << endl;
}
~Person()
{
cout << "~Person" << endl;
}
void eat()
{
? ? ? ? cout << m_strColor << endl;
? ? ? ? // cout << m_iAge << endl;
cout << "Person -- eat" << endl;
}
protected:
? ? string m_strColor;
};


/**
?* 定義工人類: Worker
?* 虛繼承人類
?*/
class Worker : ?virtual?public Person
{
public:
Worker(string name,string color):Person("Worker"+color)
{
m_strName = name;
cout << "Worker" << endl;
}
~Worker()
{
cout << "~Worker" << endl;
}
void work()
{
cout << m_strName << endl;
cout << "work" << endl;
}
protected:
string m_strName;
};


/**
?* 定義兒童類:Children
?* 虛繼承人類
?*/
class Children :?virtual?public Person
{
public:
Children(int age,string color):Person("Children"+ color)
{
m_iAge = age;
cout << "Children" << endl;
}
~Children()
{
cout << "~Children" << endl;
}
void play()
{
? ? ? ? cout<<
cout << m_iAge << endl;
cout << "play" << endl;
}
protected:
int m_iAge;
};


/**
?* 定義童工類:ChildLabourer
?* 公有繼承工人類和兒童類
?*/
class ChildLabourer:public Children,public Worker
{
public:
ChildLabourer(string name, int age,string color):Worker(name,color),Children(age,color)
{
cout << "ChildLabourer" << endl;
}


~ChildLabourer()
{
cout << "~ChildLabourer" << endl;
}
};


int main(void)
{
? ? // 用new關鍵字實例化童工類對象
ChildLabourer * p = new ChildLabourer("qq",14,"yellow");
? ? // 調用童工類對象各方法。
// ? p->eat();
? ? ? ? p->Worker::eat();
? ? ? ? p->Children::eat();
p->work();
p->play();
delete p;
p = NULL;


return 0;

}

輸出:

Person
Children
Worker
ChildLabourer
blue
Person -- eat
blue
Person -- eat
qq
work
0x60314814
play
~ChildLabourer
~Worker
~Children
~Person
如果不加virtual關鍵字時候的輸出:

Person
Children
Person
Worker
ChildLabourer
Workeryellow
Person -- eat
Childrenyellow
Person -- eat
qq
work
0x60310814
play
~ChildLabourer
~Worker
~Person
~Children
~Person
分析:

(1)不加virtual情況:

不加virtual,也就是不是虛繼承的情況下,在實例化童工這個類的時候,會按繼承順序,先調用類Children的構造函數再調用類Worker的構造函數,最后調用自己的構造函數,而調用Children和Worker的構造函數的時候又會分別先調用它們的基類Person的構造函數,這樣就會生成兩個Person的對象,從而生成兩份Person所含有的數據成員,即童工類ChildLabourer在實例化的時會生成在內存中會生成兩份Person的數據成員,所以在調用Children和Worker的eat()函數的時候,會分別打印出Workeryellow和Childrenyellow,(這里注意Children和Worker里面的eat()都是從Person繼承來的,因此分別都會打印出Person --eat;還要注意調用方式:p->Worker::eat();p->Children::eat())

銷毀對象時,會先調用自己的析構函數,再調用兩個基類的析構函數,兩個基類的析構函數調用之前都會先調用Person的析構函數。調用析構函數的順序和調用構造函數相反。

(2)加virtual的情況:

加virtual以后,從輸出結果可以看出,在實例化童工類ChildrenLabourer時,構造函數的調用順序比較正常,只調用了一次Person,析構函數的調用也只會調用一次Person的析構函數,這說明實例化童工類時只會生成一份Person的對象,表明了在對象的內存空間中僅僅能夠包含一份虛基類的對象,而且打印的結果都是blue,即ChildrenLabourer的數據不會再傳入虛基類Person。這就講數據冗余的問題解決了。

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

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

相關文章

通過syslog接收遠程日志

通過syslog接收遠程日志通過syslog接收遠程主機的日志&#xff0c;需要做一些環境配置。客戶機A通過syslog將日志信息發送到服務主機B&#xff08;或稱日志采集服務器&#xff09;。以下說明配置過程&#xff08;我的實驗環境是&#xff0c;客戶機A&#xff1a;Solaris 10&…

linux syslog服務器配置,自動發日志到另一臺日志服務器

1.客戶端:168.1.20.66修改/etc/syslog.conf 添加syslog.info 168.1.80.302.日志服務器:168.1.80.30修改/etc/sysconf/syslog 修改SYSLOGD_OPTIONS為 "-r -x -m 0" #-r表示允許接收外來的消息&#xff0c;-x表示不解析DNS, #-m 0表示時間戳標記間隔,如果指定只接…

Make文件(一)

基本規則&#xff1a; 目標&#xff1a;依賴 &#xff08;tab&#xff09;規則 目標&#xff1a;需要生成的目標文件 依賴&#xff1a;生成該目標所需的一些文件 規則&#xff1a;由依賴文件生成目標文件的手段 tab&#xff1a;每條規則前必須以tab開頭&#xff0c;使用空格不行…

移植驅動完畢后加載時的version magic報錯原因以及解決辦法

History:2012-02-17Author:yingru移植rt3070的AP驅動到裝有fedora14的PC機上時&#xff0c;模塊編譯完畢后&#xff0c;加載時提示invalid module format。PC機環境介紹&#xff1a;內核版本&#xff1a;2.6.35.6-45.fc14.i686命令行輸入dmesg查看最后的日志&#xff0c;發現如…

/proc 虛擬文件系統(實例)

Linux下有一個神奇的目錄/proc&#xff0c;經常會運行 cat /proc/cpuinfo 命令查看cpu信息&#xff0c;/proc下的確有cpuinfo文件&#xff0c;但是這個文件不是物理存在的&#xff0c;是軟件虛擬出來的&#xff0c;與普通文件不同&#xff0c;該文件是動態的。通過/proc可以實現…

內核模塊中對文件的讀寫

平時網絡部分的東西碰的多些&#xff0c;這塊一開始還真不知道怎么寫&#xff0c;因為肯定和在用戶空間下是不同的。google過后&#xff0c;得到以下答案。一般可以用兩種方法&#xff1a;第一種是用系統調用。第二種方法是filp->open()等函數。下面分別來說下這兩種方法。1…

Makefile文件試錯

1成功&#xff1a; src $(wildcard ./*cpp) obj $(patsubst %.cpp,%.o ,$(src))target test$(target) : $(obj)g $(obj) -o $(target) -I/usr/include/mysql -L/usr/lib/mysql/ -lmysqlclient %.o: %.cppg -c $< -o $ -I/usr/include/mysql -L/usr/lib/mysql/ -lmysql…

內核定時器timer_list使用

Linux內核中提供了timer使用的API&#xff0c;做一個簡單的記要。 1. 包含的頭文件&#xff1a;linux/timer.h 2. 數據類型&#xff1a;struct timer_list; 包含的主要成員&#xff1a; a. data:傳遞到超時處理函數的參數&#xff0c;主要在多個定時器同時使用時&#xff0c;區…

內存四區

1.代碼區&#xff1a; 代碼區Code&#xff0c;程序被操作系統加載到內存的時候&#xff0c;所有的可執行代碼都加載到代碼區&#xff0c;也叫代碼段&#xff0c;這塊內存是不可以在運行期間修改的。 2. 靜態區 所有的全局變量以及程序中的靜態變量都存儲在靜態區。 #include<…

最高效的進(線)程間通信機制--eventfd

我們常用的進程&#xff08;線程&#xff09;間通信機制有管道&#xff0c;信號&#xff0c;消息隊列&#xff0c;信號量&#xff0c;共享內存&#xff0c;socket等等&#xff0c;其中主要作為進程&#xff08;線程&#xff09;間通知/等待的有管道pipe和socketpair。線程還有特…

malloc,calloc,realloc

與堆操作相關的兩個函數 malloc #include<stdio.h> #include<stdlib.h> #include<string.h>int main() {char *p malloc(10); //內存隨機&#xff0c;未做處理int i;for(i 0; i < 10: i){printf(“%d “,p[i]);} free(p);return 0; } 運行結果&…

Linux內核同步機制之completion

內核編程中常見的一種模式是&#xff0c;在當前線程之外初始化某個活動&#xff0c;然后等待該活動的結束。這個活動可能是&#xff0c;創建一個新的內核線程或者新的用戶空間進程、對一個已有進程的某個請求&#xff0c;或者某種類型的硬件動作&#xff0c;等等。在這種情況下…

可變參數函數(一)

一個函數可以接受不定數的參數個數&#xff0c;這就是可變參數函數&#xff0c;比較常見的比如printf(),scanf()&#xff1b; printf(const char* format,…); printf(“%d”,i); printf(“%s”,s); printf(“the number is %d,stirng is :%s”,i,s); 變量參數函數的簡單實現&a…

Linux內核線程kernel thread詳解--Linux進程的管理與調度

內核線程為什么需要內核線程Linux內核可以看作一個服務進程(管理軟硬件資源&#xff0c;響應用戶進程的種種合理以及不合理的請求)。 內核需要多個執行流并行&#xff0c;為了防止可能的阻塞&#xff0c;支持多線程是必要的。 內核線程就是內核的分身&#xff0c;一個分身可以處…

可變參數函數(二)

函數樣例&#xff1a; #include<stdio.h> #include<stdlib.h> #include<stdarg.h>double add(int n,...) {int i 0;double sum 0;va_list argptr;va_start(argptr,n);for(i 0 ; i < n; i){double d va_arg(argptr,double);printf("%d argument …

Linux 內核網絡協議棧 ------sk_buff 結構體 以及 完全解釋 (2.6.16)

在2.6.24之后這個結構體有了較大的變化&#xff0c;此處先說一說2.6.16版本的sk_buff&#xff0c;以及解釋一些問題。一、先直觀的看一下這個結構體~~~~~~~~~~~~~~~~~~~~~~在下面解釋每個字段的意義~~~~~~~~~~~[cpp] view plaincopyprint?struct sk_buff { /* These…

可變參數輸出(三)

Linux C關于輸出函數的定義&#xff1a; int printf(const char *format,…); int vprintf(const char * format,va_list ap); int vfprintf(FILE *stream,cosnt char *format,va_list ap); int vsprintf(char *str,const char *format,va_list ap); int vsnprintf(char *str,s…

最常用的設計模式---適配器模式(C++實現)

適配器模式屬于結構型的設計模式&#xff0c;它是結構型設計模式之首&#xff08;用的最多的結構型設計模式&#xff09;。 適配器設計模式也并不復雜&#xff0c;適配器它是主要作用是將一個類的接口轉換成客戶希望的另外一個接口這樣使得原本由于接口不兼容而不能一起工作的那…

Linux 簡單打印日志(二)

#include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> //#include<windows.h> #include <unistd.h> // linux下頭文件#define FILE_MAX_SIZE (1024*1024)void get_local_time(char* buffer){time_t rawtime;struct …

程序隨筆——C++實現的一個線程池

1.線程池簡介 我們知道在線程池是一種多線程處理形式&#xff0c;處理過程中我們將相應的任務提交給線程池&#xff0c;線程池會分配對應的工作線程執行任務或存放在任務隊列中&#xff0c;等待執行。 面向對象編程中&#xff0c;創建和銷毀對象是需要消耗一定時間的&#xff0…