拐角型布局网站,Wordpress调用搜索,谁有人和兽做的网站?,女人做春梦视频网站本篇来继续说说继承。上篇可移步至【C】详细讲解继承#xff08;上#xff09;
1.继承与友元 友元关系不能继承 #xff0c;也就是说基类友元不能访问派⽣类私有和保护成员。 class Student;//前置声明class Same //基类
{
public:friend void Fun(const Same p, con… 本篇来继续说说继承。上篇可移步至【C】详细讲解继承上
1.继承与友元 友元关系不能继承 也就是说基类友元不能访问派⽣类私有和保护成员。 class Student;//前置声明class Same //基类
{
public:friend void Fun(const Same p, const Student s);//友元声明
protected:string _name;
};class Student : public Same //派生类
{
protected:int _stuid;
}; void Fun(const Same p, const Student s)
{cout p._name endl;cout s._stuid endl;
} 像上面的代码Fun函数只能访问Same基类的成员变量_name_stuid是访问不到的。 解决方法就是在派生类Student里面也加上友元声明就可以了。
class Student : public Same //派生类
{friend void Fun(const Same p, const Student s);//友元声明
protected:int _stuid;
}; 2.继承与静态成员 基类定义了static静态成员则整个继承体系⾥⾯ 只有⼀个这样的成员 。⽆论派⽣出多少个派⽣类都只有⼀个static成员实例。 class Same //基类
{
public:string _name;static int _count;//静态成员变量
};int Same::_count 0;//静态成员变量初始化class Student : public Same //派生类
{
protected:int _stuNum;
}; 我们观察一下_name的地址和_count的地址。
int main()
{Same p;Student s;cout p._name endl;cout s._name endl;cout p._count endl;cout s._count endl;return 0;
} 这⾥的运⾏结果可以看到⾮静态成员_name的地址是不⼀样的说明派⽣类继承下来了基类和派⽣类对象各有⼀份静态成员_count的地址是⼀样的说明派⽣类和基类共⽤同⼀份静态成员。 公有情况下基类和派生类指定类域都可以访问静态成员变量。
cout Same::_count endl;
cout Student::_count endl; 也可以通过对象访问。 改变其中一个另一个也改变因为这就是同一个。
cout Same::_count endl;
cout Student::_count endl;
Same::_count; //改变_count
cout p._count endl;
cout s._count endl; 3.多继承以及菱形继承
3.1 继承模型 单继承⼀个派⽣类只有⼀个直接基类时称这个继承关系为单继承 多继承⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承多继承对象在内存中的模型是先继承的基类在前⾯后⾯继承的基类在后⾯派⽣类成员在放到最后⾯。 菱形继承菱形继承是多继承的⼀种特殊情况如下。 菱形继承有数据冗余和⼆义性存在歧义的问题在Assistant的对象中Person成员会有两份。所以在实践中并不提倡设计出菱形继承的模型。 二义性问题可以通过指定访问哪个基类的成员来解决但是数据冗余问题是不能得到解决的。
如果在特定场景下一定需要设计菱形继承怎么办虚继承就出场了。 3.2 虚继承
新增了一个关键字virtual。放在会造成数据冗余和二义性的那些类上。 这里就是在Student和Teacher 加上virtual都要加只加一个都没用。
class Person
{
public:string _name; // 姓名};
// 使⽤虚继承Person类
class Student : virtual public Person
{
protected:int _num; //学号
};
// 使⽤虚继承Person类
class Teacher : virtual public Person
{
protected:int _id; // 职⼯编号
};class Assistant : public Student, public Teacher
{
protected:string _majorCourse; // 主修课程
}; 加了virtual后person在Assistant里继承的数据就只有一份了数据冗余和二义性就得到了解决。 3.3 相关小测试
假如现在有一个菱形继承关系如下 virtual应该加在哪里 加在B类和C类上。因为E里面会有数据冗余和二义性而这些冗余的数据是因为A有两份导致继承A的是B和C所以要加在B和C上不是D和C。 最后除非万不得已不要设计出菱形继承。菱形继承以及virtual的底层是特别复杂的。 3.4 多继承中指针偏移问题
先看题。
class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main()
{Derive d;Base1* p1 d;Base2* p2 d;Derive* p3 d;return 0;
}
说法正确的是 A p1 p2 p3 B p1 p2 p3 C p1 p3 ! p2 D p1 ! p2 ! p3 答案 C p1 p3 ! p2 先继承的在前面 先声明的在前面所以Base1和Base2的底层位置如下。 p3是Derive的指针指向开头。 p1是Base1的指针Base1是基类p1指向的范围是派生类Derive切出来的Base1的那部分最开始指向开头和p3一个位置。 p2与p1同理指向的范围是Derive切出来的Base2的那部分最开始指向Base2开头。 所以答案是 p1 p3 ! p2 借上面那个题说了多继承中的指针偏移问题。 4.继承和组合 public继承是⼀种is-a的关系。也就是说每个派⽣类对象都是⼀个基类对象。 组合是⼀种has-a的关系。假设B组合了A每个B对象中都有⼀个A对象。 继承允许你根据基类的实现来定义派⽣类的实现。这种通过⽣成派⽣类的复⽤通常被称为⽩箱复⽤(white-box reuse)。在继承⽅式中基类的内部细节对派⽣类可⻅ 。继承⼀定程度破坏了基类的封装基类的改变对派⽣类有很⼤的影响。派⽣类和基类间的依赖关系很强耦合度⾼。 对象组合是类继承之外的另⼀种复⽤选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接⼝。这种复⽤⻛格被称为⿊箱复⽤(black-box reuse)因为对象的内部细节是不可⻅的。对象只以“⿊箱”的形式出现。 组合类之间没有很强的依赖关系耦合度低。优先使⽤组合⽽不是继承。实际尽量多去⽤组合组合的耦合度低代码维护性好但这也不是绝对的要根据实际选择使用。 比如下面的代码就能很好解释继承和组合。
class Tire //轮胎
{
protected:string _brand; // 品牌size_t _size; // 尺⼨
};
class Car //车
{
protected:string _colour; // 颜⾊string _num; // ⻋牌号Tire _t1; // 轮胎Tire _t2; // 轮胎Tire _t3; // 轮胎Tire _t4; // 轮胎
};
轮胎和车就比较符合 has-a 的关系车有轮胎用的组合。 class BMW : public Car //继承
{
public:void Drive() { cout BMW endl; }
};class Benz : public Car //继承
{
public:void Drive() { cout Benz endl; }
};
上面的代码是继承BMW 和 Benz 是品牌比较符合 is-a 的关系BMW和Benz是车。 本次分享就到这里了我们下篇见~