C++中的继承特性(2)
来源:互联网 发布:七雄战记更新网络错误 编辑:程序博客网 时间:2024/05/31 15:18
4.static成员与继承
在类中,无论创建了多少个对象,被static修饰的成员变量永远只有一个,那么派生类是否也继承了这个静态成员变量呢?
假设一:派生类继承了这个变量,且与基类共享同一个静态成员;
假设二:派生类拷贝了这个变量,不与基类共享,是派生类所有对象共有的static静态成员。
这一点其实很好证明。由上一篇博文我们基本理解了派生类的构造函数和析构函数,那么这里就利用构造函数和析构函数来验证哪一种假设正确。
我们来看下面一段代码:
class A{public: A(){ ++_a; cout << "A: _a = " << _a << endl; } ~A(){ --_a; cout << "~A: _a = " << _a << endl; } static int _a;};int A::_a = 0;class B :public A{public: B(){ cout << "B: _a = " << _a << endl; } ~B(){ cout << "~B: _a = " << _a << endl; }};void FunTest(){ A a; B b;}int main(){ FunTest(); system("pause"); return 0;}
阅读上段代码,分析可得:
<1>在假设一下,创建对象a时使静态成员变量_ a自增,创建对象b时将在初始化列表中调用A(),使_ a自增,此时_ a为2;销毁对象b时先调用~B(),再调用~A()使_ a自减,此时_ a为1,销毁对象a时再次使_ a自减,最终为零,故此时应在屏幕上输出如下结果:
A: _a = 1A: _a = 2B: _a = 2~B: _a = 1~A: _a = 1~A: _a = 0
<2>在假设二下,创建对象a时使A::_ a自增至1,创建对象b时调用A()使B类自己的静态成员_ a自增至1;销毁对象b时先调用~B(),再调用~A()使B类自己的静态成员_ a自减至0,销毁对象a时使A::_ a自减至0,此时应在屏幕上输出如下结果:
A: _a = 1A: _a = 1B: _a = 1~B(): _a = 1~A: _a = 1~A: _a = 0
而后在VS中运行上述程序代码,得到结果如下图:
验证假设一正确!即所有的派生类与基类共享相同的static静态成员变量。
5.继承的分类
1)单继承
一个子类只有一个直接父类称为单继承。单继承结构简单且易于理解,示意图如下:
2)多继承
一个子类有多个直接父类称为多继承,示意图如下:
6.虚继承
在多继承中,会出现如下一种继承方式——菱形继承:
我们通过如下一段代码观察一个Three对象中各个变量的存放:
class Zero{public: int zero;};class One :public Zero{public: int one;};class Two :public Zero{public: int two;};class Three :public One, public Two{public: int three;};void FunTest(){ Three t; t.One::zero = 0; t.one = 1; t.Two::zero = 2; t.two = 3; t.three = 4;}int main(){ FunTest(); system("pause"); return 0;}
代码执行的内存截图如下:
首先从内存视图中我们可以看到:1.类中的成员变量存放次序是先父类,后本类;2.若父类不只一个,将按继承的顺序依次存放。
其次,很明显这样会使得一个Three的对象中存在两个Zero的对象,如果我们的本意不是这样,将造成数据冗余和空间浪费。为解决此问题,C++出现了虚拟继承——即将共同基类设置为虚基类,当出现了共同基类时,就只有一个基类对象,同名数据成员仅有一份拷贝,同一个函数名也只有一个映射,解决了二义性问题、节省了内存空间、避免了数据不一致的问题(参考http://blog.csdn.net/crystal_avast/article/details/7678704)。
虚继承格式为: class <派生类类名> :virtual 继承方式 <基类名>
那么同样,我们来研究一下虚继承情况下上述Three类对象的内存空间,修改后的代码如下:
class Zero{public: int zero;};class One :virtual public Zero{public: int one;};class Two :virtual public Zero{public: int two;};class Three :public One, public Two{public: int three;};void FunTest(){ Three t; t.One::zero = 0; t.one = 1; t.Two::zero = 2; t.two = 3; t.zero = 0; t.three = 4;}int main(){ cout << sizeof(Three) << endl; FunTest(); system("pause"); return 0;}
调试上述代码,首先得到Three这个类的大小为24Byte,在执行FunTest函数后观察内存可以看到:
分析此时的内存布局,是如下情况:
再分别进入两个地址,得到0110e0a4所指向的空间如下图,发现前四个字节为0,后四个字节值为20,正好是t中one类对象与zero对象地址的差值:
得到0110e1a8所指向的空间如下,同理得到后四个字节值是two对象与zero对象地址的差值:
故而对于有两个基类的虚继承,内存布局如下图所示:
通过查阅其它博客(http://blog.chinaunix.net/uid-16723279-id-3568748.html)关于虚继承的讨论,得到在虚继承的情况下内存空间分布为:
1、B1的虚函数表(子类重定义的基类的虚函数、重定义的B1的虚函数、子类自己的虚函数)
2、继承自B1的数据成员
3、B2的虚函数表(子类重定义的基类的数据成员、重定义的B2的虚函数)
4、继承自B2的数据成员
5、子类自己的数据成员
6、基类的虚函数表(子类重定义的虚函数、基类的虚函数)
7、基类的数据成员
以上仅为博主初学认知,如有错误或不当之处,欢迎批评指正!
- C++中的继承特性(2)
- C++中的继承特性(1)
- javascript中的继承特性
- objective-c中的特性
- objective-c中的特性
- 【C++】c++中的继承
- Objective-c中的C特性
- Object-C中的特性-----property
- Objective-C中的属性特性
- 浅谈Objective-C中的继承
- 【C++】浅谈C++中的继承
- 【C++】浅析C++中的继承
- 继承特性
- 继承中的成员变量的特性(私有成员的访问方法)
- Objective-C基础(面向对象--下--三大特性--继承、多态)
- objective-c中的cocoa特性:KVC-键值编码(十三)
- 【C++】继承(菱形继承)
- C++中的公有继承(public)问题
- 263. Ugly Number
- 【小组】探空气球项目的分工与目标
- Android-Fragment 切换属性动画
- 意外断电开库触发ORA-01207
- Tomcat:基础安装和使用教程
- C++中的继承特性(2)
- JavaWeb实现文件上传下载功能实例解析
- 源码开放学ARM—DM9000网卡驱动
- 第八周拓展实践(1)小明借书
- 定点乘法运算之原码一位乘法
- Git 安装配置
- php 生成器 入门理解
- Struts2+Spring3+Hibernate4+Maven+EasyUI(1)
- 1