[转载]C++第一部分学习:继承(四)

标签:
转载 |
分类: 计算机相关 |
隐藏带来的访问错误
class Base
};
class Derived : public Base
{
};
Derived
int a = d.doit(12.6);
分析:
d 对象是Derived类的,于是编译器将定位于该作用域,此时,尽管由于全盘接受使子类作用域有两个doit,但由于同名,使父类公有那个doit被隐藏,可用的只有int doit( int ).而这个函数是私有的,因此,调用错误.
该隐藏机制甚至可以不必拘泥于一个函数名。子类的同名数据成员足以隐藏父类的同名成员 。
不要用存取权限分辨同名二义
class Base1
{
};
class Base2
{
};
class Derived : public Base1 ,public Base2
{
Derived
int a = d.doit();
虽然一个是private,一个是public,但是存取权限不具有多态性!
错误!
编译器将此调用视为模棱两可。
只能写为:
d.Base1:: doit();
d.Base2:: doit();
路径二义性问题
class B
};
class B1 : public B {
};
class B2 : public B {
};
class D : public B1,public B2
{
};
void
{
}
子类D对象的存储结构示意图:
路径二义的含义:
类间继承关系组成了一个菱形,到底是哪个b?
固然可以用类名::加以区别,但
虚基类
l
–
l
–
例:class B1: virtual
l
–
–
l
–
虚基类举例
class B
class B1 : virtual public B { private: int b1;};
class B2 : virtual public B { private: int b2;};
class D: public B1, public B2{ private: float d;};
在子类对象中,最远基类成分是唯一的。于是下面的访问是正确的:
D
dobj.b;
虚基类派生的对象存储结构示意图:
真正的实现机制
l
l
l
l
l
l
有同学问:既然两个父类中有两套祖父类的成员,随便找一个去掉就行了啊。要注意,子类继承了两个父类,就应该保证子类对象中包含完整的两个父类的成员,若擅自去掉其中一个,则造成子类中的父类部分不完整。
#include <iostream>
using namespace std;
class B0
{ public:
};
class B1: virtual public B0
{ public:
};
class B2: virtual public B0
{
};
class D1: public B1, public B2
{
};
void main()
{
}
编译器自动为指对象插入了“内部调整指针”,这不是“指向成员的针”,而是指向“调整量数组”的指针。因为基类B0会含有多个成员,这些成员都要被调整走,不可能用一个指针指向多个成员,因此需要一个“调整量数组” 。
这个“内部调整指针”简称其为“指针”,它占4个字节(一个字长),当然它仍然遵循对齐原则。
这个“内部调整指针”不是只出现在孙类对象中,在两个子类的对象中就已存在了(若产生对象的话才能看到)。
可以看出,编译器外加的“内部调整指针”和“调整量数组”都是用于对象数据成员的,与函数成员无关。函数在继承时是“共享的”而不是“含有”,不占用对象空间,也就不用调整。
虚基类再例
class B
class B1 : virtual public B { };
class B2 : virtual public B { };
class D: public B1, public B2{
现在对各类测试大小:
你认为应该是几?大概很意外!
1
4
4
8
算类对象大小时,不用考虑成员函数,他们是共享的,不占用数据空间。如果一个类是空类,因为要保证new一个这个类的对象时,不出现大小为0的违反原理的情况,编译器默认空类对象占了1个大小的位置。而虚拟继承了空类的空类因为隐含了一个调整量指针,所以大小为4,D中含有了两个调整量指针,所以大小为8。
作者声明:本文中使用的ppt内容、图片内容版权归东软侯克林老师所有,转载请注明出处,不得用于商业目的