设计接单网站大全,wordpress前台投稿上传图片大小,办公空间设计公司有哪些,中国万网官网域名续费一、友元函数的继承
友元函数不能被继承#xff0c;就像爸爸的朋友不是你的朋友#xff0c;如果要有友元函数#xff0c;在子类重新定义一个。
二、静态成员的继承
静态成员的继承仍然是那个成员#xff0c;普通成员的继承是不同的。
父类的静态成员属于当前类#xf…一、友元函数的继承
友元函数不能被继承就像爸爸的朋友不是你的朋友如果要有友元函数在子类重新定义一个。
二、静态成员的继承
静态成员的继承仍然是那个成员普通成员的继承是不同的。
父类的静态成员属于当前类也属于当前类的派生类。
三、单继承与多继承
1、单继承
一个子类只有一个直接父类 2、多继承
一个子类有两个或以上的直接父类 四、菱形继承
1、理解 如图 Assistant 就是一个菱形继承显然如果不做特殊处理 Assistant 里面会有两份 Person 类中的成员这就导致了数据冗余和二义性。
解决办法就是在菱形继承中父类被继承两次的地方进行虚继承virtual
被继承的 Person 类是虚基类。
2、剖析
1未用 virtual
class A
{
public:int _a;
};class B : public A
//class B : virtual public A
{
public:int _b;int _b1;int _b2;};class C : public A
//class C : virtual public A
{
public:int _c;
};
class D : public C, public B
{
public:int _d;
};int main()
{D d;d.B::_a 1;d.C::_a 2;//d._a 0;d._b 3;d._c 4;d._d 5;
}
上图就是典型的菱形继承且没有解决这样在D类中我们发现两个_a是不一样的要想使用必须指定类域这就是数据冗余和二义性。
内存级理解 明显的看到内存中D对象中的BC存有不同的_a这是不被允许的。
2用 virtual
class A
{
public:int _a;
};//class B : public A
class B : virtual public A
{
public:int _b;int _b1;int _b2;};//class C : public A
class C : virtual public A
{
public:int _c;
};
class D : public C, public B
{
public:int _d;
};int main()
{D d;d.B::_a 1;d.C::_a 2;d._a 0;d._b 3;d._c 4;d._d 5;
}
上图我们用虚继承解决了问题此时类D中的_a是同一个_a所以最后_a值应该是0
内存级理解 首先BC类中不再存有_a的值而是用一个地址代替了_a的值被放到了D对象的内存最下面地址所指向的内容存放的是_a的值0还有十六进制的偏移量用来找到原内存中_a的存储位置。
这样就解决了问题。
3总结
a、存地址的偏移量是为了方便找到数据方便切片。
b、虚继承的解决原理把原来存父类成员的地方存地址通过地址和偏移量找到唯一的父类成员。实现原来有几个类继承就有几份父类成员的数据冗余变成现在存几个地址和偏移量来找到内存中唯一的一份父类成员解决了数据冗余和二义性。
c、对象的存储按声明顺序存储。
五、继承和组合
我们发现继承和组合都能复用之前的类两者是相似的在实践中两者也会一起使用。
//父类
class A {};//继承
class B : public A
{//直接继承直接使用
};//组合
class C
{
private:A _aa; //创建 A 对象使用成员及方法
}
方式备注继承is_a关系白箱复用在继承方式中基类的 内部细节对子类可见 。继承一定程度破坏了基类的封装基类的改变对派生类有很大的影响耦合度高。组合has_a关系黑箱复用为对象的内部细节是不可见的耦合度低。
优先使用组合组合的耦合度低代码维护性好。