虚继承

------------------siwuxie095

看如下实例:

有 4 个类,其中:类 A 是父类,类 B 和 类 C 都继承 类 A,

而 类 D 继承了 类 B 和 类 C,称这种继承关系为 菱形继承

在菱形继承中,既有多继承,又有多重继承:

那么问题来了:

当实例化 D 的对象时,发现:D 是从 B 继承来的,B 是从 A 继承来的,

D 也是从 C 继承来的,C 是从 A 继承来的

这样,D 中将含有两个完全一样的 A 的数据,这种情况是不能容忍的,

因为在一个对象中有两份完全相同的数据,无法承担这种冗余数据带来

的系统开销,所以必须要解决

也许,你会说在实际的工作中会遇到这么复杂的情况吗?

看如下实例:人、工人、农民、农民工间的菱形继承关系

那么,可以使用 虚继承 来解决这种典型的菱形继承关系带来的数据冗余问题

虚继承

虚继承 是继承的一种方式,关键字:virtual

看如下实例:virtual 可以写在 public 的前面 或 后面,推荐前面

其中:Worker 和 Farmer 都 虚继承 自 Person

在使用时:

MigrantWorker 可以继承自 Worker 和 Farmer 这两个类,并称 Worker

和 Farmer 为 虚基类,当使用 MigrantWorker 实例化一个对象时,它当

中只含有一份 Person 的数据

程序 1:不使用虚继承

Person.h:


#ifndef PERSON_H

#define PERSON_H

//重定义,即在当前的工程中,Person被定义了两遍,因为在子类包含了两个 Person.h

//

//在菱形继承中重定义必然会出现

//用宏定义来解决重定义,避免了重复包含

//具体用法:在公共被继承的类中写上宏定义

//

//推荐不是公共被继承的类也写上,将来这个类被其他类继承时就不会出现重定义

#include <string>

using namespace std;

class Person

{

public:

Person(string color = "yellow");

virtual ~Person();//虚析构函数

void printColor();

protected:

string m_strColor;//肤色

};

#endif

Person.cpp:


#include "Person.h"

#include <iostream>

using namespace std;

Person::Person(string color)

{

m_strColor = color;

cout << "Person()" << endl;

}

Person::~Person()

{

cout << "~Person()" << endl;

}

void Person::printColor()

{

cout << "Person--printColor()" << endl;

cout << m_strColor << endl;

}

Farmer.h:


#include "Person.h"

#include <string>

using namespace std;

class Farmer :public Person

{

public:

Farmer(string name = "Jack", string color = "yellow");

virtual ~Farmer();//虚析构函数

void sow();

protected:

string m_strName;

};

Farmer.cpp:


#include "Farmer.h"

#include <iostream>

using namespace std;

//color是string型数据所以可以用 + 的形式来将 "Farmer " 同时传进去作为标记

Farmer::Farmer(string name, string color) :Person("Farmer "+color)

{

m_strName = name;

cout << "Farmer()" << endl;

}

Farmer::~Farmer()

{

cout << "~Farmer()" << endl;

}

void Farmer::sow()

{

cout << "Farmer--sow()" << endl;

cout << m_strName << "," << m_strColor << endl;

}

Worker.h:


#include "Person.h"

#include <string>

using namespace std;

class Worker:public Person

{

public:

//希望Worker可以传入肤色给Person,

//使得Person能从Worker的参数列表中拿到肤色的这个参数

Worker(string code = "001", string color = "yellow");

virtual ~Worker();//虚析构函数

void carry();

protected:

string m_strCode;

};

Worker.cpp:


#include "Worker.h"

#include <iostream>

using namespace std;

//color是string型数据所以可以用 + 的形式来将 "Worker " 同时传进去作为标记

Worker::Worker(string code, string color) :Person("Worker "+color)

{

m_strCode = code;

cout << "Worker()" << endl;

}

Worker::~Worker()

{

cout << "~Worker()" << endl;

}

void Worker::carry()

{

cout << "Worker--worker()" << endl;

cout << m_strCode << "," << m_strColor << endl;

}

MigrantWorker.h:


#include "Farmer.h"

#include "Worker.h"

class MigrantWorker:public Farmer,public Worker

{

public:

MigrantWorker(string name, string code, string color);

virtual ~MigrantWorker();//虚析构函数

};

MigrantWorker.cpp:


#include "MigrantWorker.h"

#include <iostream>

using namespace std;

MigrantWorker::MigrantWorker(string name, string code, string color) :Farmer(name, color),

Worker(code, color)

{

cout << "MigrantWorker()" << endl;

}

MigrantWorker::~MigrantWorker()

{

cout << "~MigrantWorker()" << endl;

}

main.cpp:


#include <stdlib.h>

#include "MigrantWorker.h"

#include <iostream>

using namespace std;

int main(void)

{

//从堆中实例化,用指针指向堆中的这块内存

MigrantWorker *p = new MigrantWorker("Merry", "200", "white");

cout << endl;

//这两行代码说明了Person类在MigrantWorker类中有两份数据

//即MigrantWorker类中有两份继承自Person类的数据数据冗余系统开销太大

p->Farmer::printColor();

p->Worker::printColor();

cout << endl;

delete p;

p = NULL;

system("pause");

return 0;

}

运行一览:

程序 2:使用虚继承

Person.h:


#ifndef PERSON_H

#define PERSON_H

#include <string>

using namespace std;

class Person

{

public:

Person(string color = "yellow");

virtual ~Person();

void printColor();

protected:

string m_strColor;

};

#endif

Person.cpp:


#include "Person.h"

#include <iostream>

using namespace std;

Person::Person(string color)

{

m_strColor = color;

cout << "Person()" << endl;

}

Person::~Person()

{

cout << "~Person()" << endl;

}

void Person::printColor()

{

cout << "Person--printColor()" << endl;

cout << m_strColor << endl;

}

Farmer.h:


#include "Person.h"

#include <string>

using namespace std;

class Farmer :virtual public Person //Farmer变成了虚基类

{

public:

Farmer(string name = "Jack", string color = "yellow");

virtual ~Farmer();

void sow();

protected:

string m_strName;

};

Farmer.cpp:


#include "Farmer.h"

#include <iostream>

using namespace std;

Farmer::Farmer(string name, string color) :Person("Farmer "+color)

{

m_strName = name;

cout << "Farmer()" << endl;

}

Farmer::~Farmer()

{

cout << "~Farmer()" << endl;

}

void Farmer::sow()

{

cout << "Farmer--sow()" << endl;

cout << m_strName << "," << m_strColor << endl;

}

Worker.h:


#include "Person.h"

#include <string>

using namespace std;

class Worker :virtual public Person //Worker变成了虚基类

{

public:

Worker(string code = "001", string color = "yellow");

virtual ~Worker();

void carry();

protected:

string m_strCode;

};

Worker.cpp:


#include "Worker.h"

#include <iostream>

using namespace std;

Worker::Worker(string code, string color) :Person("Worker "+color)

{

m_strCode = code;

cout << "Worker()" << endl;

}

Worker::~Worker()

{

cout << "~Worker()" << endl;

}

void Worker::carry()

{

cout << "Worker()" << endl;

cout << m_strCode << "," << m_strColor << endl;

}

MigrantWorker.h:


#include "Farmer.h"

#include "Worker.h"

class MigrantWorker :public Farmer, public Worker

{

public:

MigrantWorker(string name, string code, string color);

~MigrantWorker();

};

MigrantWorker.cpp:


#include "MigrantWorker.h"

#include <iostream>

using namespace std;

MigrantWorker::MigrantWorker(string name, string code, string color) :Farmer(name, color),

Worker(code, color)

{

cout << "MigrantWorker()" << endl;

}

MigrantWorker::~MigrantWorker()

{

cout << "~MigrantWorker()" << endl;

}

main.cpp:


#include <stdlib.h>

#include "MigrantWorker.h"

#include <iostream>

using namespace std;

int main(void)

{

MigrantWorker *p = new MigrantWorker("Merry", "200", "white");

cout << endl;

//此时只会打印出yellow 说明在虚继承的情况下作为菱形继承最顶层的父类,

//并没有进行参数的传递

//

//参数只使用了顶层父类的默认参数而无法从子类中获得传入的参数

p->Farmer::printColor();

p->Worker::printColor();

cout << endl;

/*p->carry();

p->sow();*/

delete p;

p = NULL;

system("pause");

return 0;

}

运行一览:

【made by siwuxie095】

时间: 2024-10-12 23:29:31

虚继承的相关文章

C++ 虚函数和虚继承浅析

本文针对C++里的虚函数,虚继承表现和原理进行一些简单分析,有希望对大家学习C++有所帮助.下面都是以VC2008编译器对这两种机制内部实现为例. 虚函数 以下是百度百科对于虚函数的解释: 定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数[1] 语法:virtual 函数返回类型 函数名(参数表) { 函数体 } 用途:实现多态性,通过指向派生类的基类指针,访问派生类中同名覆盖成员函数 函数声明和定义和普通的类成员函数一样,只是在返回值之前加入了关键字"vir

多继承(虚继承)派生类对象内存结构

在这里谈一下虚继承.前面写过派生类对象的内存结构,都是基于VS2010编译器的,不同的编译器对于继承的处理不同,但本质都是一样的. 虚继承是解决共享基类问题的.例如在菱形继承中 如果不使用虚继承,基类A在D中会有两个,这不仅浪费内存,还会造成歧义.使用虚继承就可以解决基类共享的问题. 要想在派生类中共享基类(例如在D对象中只有一个A对象,这时候D对象中的B对象和C对象都可以查找到A,而不是在B对象和C对象中各含有一个A对象). 先看下面一个例子: #include<iostream> usin

sizeof 和类继承 虚继承 求类大小

代码: #include <iostream> using namespace std; /* class a{ float k; // 4字节 virtual void foo(){} //有一个4字节的指针指向自己的虚函数表 }; class b : virtual public a{ virtual void f(){} }; 有这样的一个指针vptr_b_a,这个指针叫虚类指针,也是四个字节:还要包括类a的字节数,所以类b的字节数就求出来了. 运行结果: 8 16 */ /* clas

C++多重继承中的虚继承和虚函数举例

上一篇虚继承举例:http://10638473.blog.51cto.com/10628473/1964414 本文将A类中的show()函数前加上virtual关键字. //多重继承 #include <iostream> using namespace std; class A { public:     int a;     A(int a=0):a(a)     {         cout<<"A基类A::A()"<<endl;     

多重继承,虚继承,MI继承中虚继承中构造函数的调用情况

先来测试一些普通的多重继承.其实这个是显而易见的. 测试代码: [cpp] view plain copy print? //测试多重继承中派生类的构造函数的调用顺序何时调用 //Fedora20 gcc version=4.8.2 #include <iostream> using namespace std; class base { public: base() { cout<<"base created!"<<endl; } ~base()

看到的关于虚函数继承及虚继承解释比较好的文章的复制

(来源于:http://blog.chinaunix.net/uid-25132162-id-1564955.html) 1.空类,空类单继承,空类多继承的sizeof #include <iostream> using namespace std; class Base1 { }; class Base2 { }; class Derived1:public Base1 { }; class Derived2:public Base1, public Base2 { }; int main(

C++构造函数 &amp; 拷贝构造函数 &amp; 派生类的构造函数 &amp; 虚继承的构造函数

构造函数 ,是一种特殊的方法 .主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 .特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载.(摘自百度百科构造函数). 一.最基本的构造函数 1 class Base 2 { 3 public: 4 Base(int var) : m_Var(var) 5 { 6 } 7 private: 8 int m_Var; 9 }; 以上构造函数的执行过程:

C++中的虚继承 &amp; 重载隐藏覆盖的讨论

虚继承这个东西用的真不多.估计也就是面试的时候会用到吧.. 可以看这篇文章:<关于C++中的虚拟继承的一些总结> 虚拟基类是为解决多重继承而出现的. 如:类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

虚函数列表: 取出方法 // 虚函数工作原理和(虚)继承类的内存占用大小计算 32位机器上 sizeof(void *) // 4byte

#include <iostream> using namespace std; class A { public: A(){} virtual void geta(){ cout << "A:A" <<endl; } virtual void getb(){ cout << "A:B" <<endl; } }; class B :public A{ public: B(){} virtual void g