c++ 虚继承与继承的差异 (转)
转自:CSDN dqjyong
原文链接:http://blog.csdn.net/dqjyong/article/details/8029527
前面一篇文章,说明了在C++ 虚继承对基类构造函数调用顺序的影响。经过仔细推敲,发现没有彻底说清楚虚继承与普通继承之间的关系。所以用下面的文字再说明一下。
首先,重复一下虚拟继承与普通继承的区别有:
假设derived 继承自base类,那么derived与base是一种“is a”的关系,即derived类是base类,而反之错误;
假设derived 虚继承自base类,那么derivd与base是一种“has a”的关系,即derived类有一个指向base类的vptr。
因此虚继承可以认为不是一种继承关系,而可以认为是一种组合的关系。因为虚继承有着“继承”两个关键字,那么大部分人都认为虚继承与普通继承的用法没什么太大的不同。由此用在继承体系中,这种将虚继承认为是普通继承的危害更佳大。下面先用一个例子来说明问题:
class base
{
public:
base(){cout<<"base::base()!"<<endl;}
void printBase(){cout<<"base::printBase()!"<<endl;}
}; class derived:public base
{
public:
derived(){cout<<"derived::derived()!"<<endl;}
void printDerived(){cout<<"derived::printDerived()!"<<endl;}
};
上面是普通继承实现,在实际应用中,我们可以使用下面的代码进行类型转换:
int main(int argc, const char * argv[])
{
derived oo;
base oo1(static_cast<base>(oo));
oo1.printBase();
derived oo2 = static_cast<derived&>(oo1);
oo2.printDerived();
return ;
}
编译无错误,而且会得出正确的结果。其结果为:
base::base()! derived::derived()! base::printBase()! derived::printDerived()!
而将上面的普通继承变成虚拟继承,如下代码:
class base1
{
public:
base1(){cout<<"base::base()!"<<endl;}
void printBase(){cout<<"base::printBase()!"<<endl;}
}; class derived1:virtual public base1
{
public:
derived1(){cout<<"derived::derived()!"<<endl;}
void printDerived(){cout<<"derived::printDerived()!"<<endl;}
}; int main(int argc, const char * argv[])
{
derived1 oo;
base1 oo1(static_cast<base1>(oo));
oo1.printBase();
derived1 oo2 = static_cast<derived1&>(oo1);
oo2.printDerived();
return ;
}
编译上面的代码,提示如下:

可以看到不能将基类通过static_cast转换为继承类。我们知道c++提供的强制转换函数static_cast对于继承体系中的类对象的转换一般是可行的。那么这里为什么就不可以了呢?还是需要从虚拟继承的内部实现来说明问题。
virtual base class的原始模型是在class object中为每一个有关联的virtual base class加上一个指针vptr,该指针指向virtual基类表。有的编译器是在继承类已存在的virtual table直接扩充导入一个virtual base class table。不管怎么样由于虚继承已完全破坏了继承体系,不能按照平常的继承体系来进行类型转换。
不管怎么样,虚继承在类型转换是一定要十分注意。不要轻易使用虚继承,更不要在虚继承的基础上进行类型转换,切记切记!
c++ 虚继承与继承的差异 (转)的更多相关文章
- 【整理】C++虚函数及其继承、虚继承类大小
参考文章: http://blog.chinaunix.net/uid-25132162-id-1564955.html http://blog.csdn.net/haoel/article/deta ...
- C#虚基类继承与接口的区别
类:定义新的数据类型以及这些新的数据类型进行相互操作的方法 定义方式: class Cat { } class Cat:object { } C#中所有的类都是默认由object类派生来的,显示指定或 ...
- C++中的继承(1) 继承方式
1.继承与派生 继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一.简单的说,继承是指一个对象直接使用另一对象的属性和方法.继承呈现了 面向对象程序设 计的层次结构, 体现了 由简单 ...
- C++中的类继承之单继承&多继承&菱形继承
C++中的类继承之单继承&多继承&菱形继承 单继承是一般的单一继承,一个子类只 有一个直接父类时称这个继承关系为单继承.这种关系比较简单是一对一的关系: 多继承是指 一个子类有两个或 ...
- web前端开发必懂之一:JS继承和继承基础总结
首先,推荐一篇博客豪情的博客JS提高: http://www.cnblogs.com/jikey/p/3604459.html ,里面的链接全是精华, 一般人我不告诉他; 我们会先从JS的基本的设计模 ...
- C++学习笔记14,private/protected/public继承,私有继承,保护继承,公有继承(五)(总结)
各种继承方式: 特征 公有继承 保护继承 私有继承 公有成员变为 派生类的公有成员 派生类的保护成员 派生类的私有成员 保护成员变为 派生类的保护成员 派生类的保护成员 派生类的私有成员 私有成员变为 ...
- js原生设计模式——2面向对象编程之继承—原型继承(类式继承的封装)
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- Day7 类的继承和继承实现的原理
继承可以分为但继承,多继承. 继承的基本形式 class ParentClass1(object): #定义父类 pass class ParentClass2: #定义父类 pass class S ...
- 深入浅出javascript(十二)继承——构造函数继承和组合继承
#题记: 有一水果类,抽象出属性包括:name(水果品种),price(价格),id(ID号).现有两个子类,分别为苹果,桔子,希望继承水果父类. 一.构造函数继承 构造函数继承相当把父类的属性在子类 ...
随机推荐
- 孤岛能源安卓游戏android源码
孤岛能源是一个以孤岛为背景的模拟动作游戏,游戏中你的角色是 Android 机器人,目的是找到该岛上充满能量的能源造福人类.游戏中,你可以选择按键操作,也可以选择触摸操作.希望你能顺利完成任务. ...
- OrCAD Capture CIS与Allegro交互布局
激活OrCAD与Allegro的交互程序 1. 打开原题图,Options->Preference在Miscellaneous里勾选 2. 同时打开OrCAD原理图设计界面及Allegro PC ...
- jquery 1.6发布后,增加prop()方法部分取代attr()方法
以前的jq中,全部使用attr来访问对象的属性,比如取一个图片的alt属性,就可以这样做$('#img').attr('alt'); 但是在某些时候,比如访问checkbox的disabled属性 ...
- 联想预装win8系统改成win7操作步骤及注意事项
联想消费台式机与一体机预装Windows8改装Windows7的操作步骤及常见问题 前提说明: 目前联想出厂预装Windows 8的台式和一体机使用都是UEFI+GPT硬盘的组合,并且开启了安全启动, ...
- Silverlight形状、画笔、变换、图像处理、几何图形
1.形状(Ellipse.Line.Path.Polygon.Polyline 和 Rectangle) <UserControl x:Class="SharpStudy.MainPa ...
- res/raw文件的存放和读取
通常,如果Android开发者有些文件比如音频,视频,.html,.mp3等等这些文件不希望编译器编译而保持原始原貌打包进apk文件(这在游戏开发中很常见和普遍,如游戏用到的游戏音乐.图等资源),那么 ...
- 解决Handler与Activity同步冲突
这个问题可以由Handler的一个子类HandlerThread来解决. 程序参考自Mars老师的Android课程第一季第十五集. 代码以及注释有所改动,如下: package com.handle ...
- Extjs combox的详解
Extjs combox的详解 写了哈extjs当中的combox,第一次写,照着网上的例子抄.在上次的例子中,是实现了,可是有一个重大的错误.也就是自己根本没有理解combox从远程服务器获取数据, ...
- Oracle 中的replace函数的应用
replace 函数用法如下: replace('将要更改的字符串','被替换掉的字符串','替换字符串') oracle 中chr()函数 CHR() --将ASCII码转换为字符 语法CHR(nu ...
- ubuntu 12.04版本出现界面终端打开broken pipe,但是tty1这些可以。
sudo apt-get remove xserver-xorg sudo apt-get install xserver-xorg