继承(一):https://blog.csdn.net/ly_6699/article/details/88801492
讲到继承的概念和定义,基类和派生类对象赋值转换
继承(二):https://blog.csdn.net/ly_6699/article/details/88805464
讲到继承中的作用域和派生类的默认成员函数
今天,我们接着前两天的内容继续讲继承。本节内容主要有 继承和友元,继承和静态函数,继承和组合
5.继承和友元
这里只需要注意一点,友元关系不能继承! 也就是说:基类的友元不能访问子类的private 和protected 成员。
class Student; //声明一个类
class Person
{
public:
friend void Display(const Person & p, const Student&s);
protected:
string _name;
};
class Student :public Person
{
protected:
int _No;
};
void Display(const Person& p, const Student& s)
{
cout << p._name << endl;
//下面编译不通过,因为基类的友元函数无法访问派生类成员
cout << s._No << endl;
}
6. 继承和静态成员
若在基类中定义了static 静态成员,则无论派生出多少子类,整个继承体系内只有一个这样的成员。
例题:计算共创建了多少个对象。
class Person
{
public:
Person() { ++_count; }
protected:
string _name;
public:
static int _count; //统计人数
};
int Person::_count = 0; //静态成员要在类外定义
class Student :public Person
{
protected:
int _No;
};
class Graduade :public Student
{
protected:
int _ID;
};
void Test()
{
Student s1;
Student s2;
Student s3;
Graduade g1;
cout <<"人数:"<< Person::_count << endl; //4
Student::_count = 0;
cout << "重置后人数:" << Person::_count << endl; //0
}
由重置后人数为0,即可得出结论:基类中定义的static成员在整个继承体系在只有这一个
7.继承和组合
我们都知道,类复用有三种方式:
A.模板:一般是类型的复用
B.继承:常用的public继承是 is-a 关系
C.组合:是一种 has-a的关系
模板的内容我在之前的模板初阶 和 模板进阶 两章博客中中已经讲的很多了,想了解的可以直接点链接去看。这里我就只讲一下继承和组合:
- public 继承是一种 is-a 的关系。也就是说每个派生类对象都是一个基类对象。
比如我们平时会说学生是人,所以学生和人两个类间应该是继承关系
- 组合是一种 has-a 的关系。假设B组合了A,每个B对象中都有一个A对象。
比如我们说学生有学号,所以学生和学号两个类间应该是组合关系
-
我们一般优先使用对象的组合,而不是类的继承。因为对象组合有助于我们保证每个类的封装性(原因是组合使用黑箱复用)。
-
继承允许我们根据基类的实现来定义派生类的实现。这种通过生成派生类的复用被称为白箱复用。这里的术语“白箱”是相对可视性而言的:在继承方式中,基类的内部细节对于子类是可见的。但继承在一定程度上破坏了基类的封装性,并且基类的改变对派生类有很大的影响。这里派生类和基类间的依赖关系很强,耦合度很高。
-
对象组合也是代码复用的一种方式。对于类外要增加新的更复杂的功能,我们可以通过组装或组合对象来获得。这里对象的组合要求被组合的对象具有良好定义的接口。这种只提供接口的复用被称为黑箱复用。因为对象内部细节是不可见的。 组合类之间没有很强的依赖关系,耦合度低。
-
对于较好的软件设计,我们一般要求模块内高内聚,模块间低耦合。所以我们尽量多使用组合,它的耦合度低,代码维护性好。
-
组合和继承各有用武之地,博主只是在既可以用继承也可以用组合的情况下更推荐用组合。但是如果有些关系是很明显的 is-a关系,我们就选择用继承,另外如果我们要实现多态也必须用继承。
继承的应用如下:
//Car和BMW,Benz 构成is-a 的关系 宝马是车,奔驰是车
class Car
{
protected:
string _colour = "白色"; //颜色
string _num = "陕A123"; //车牌号
};
class BMW :public Car
{
public:
void Drive()
{
cout << "简单" << endl;
}
};
class Benz :public BMW
{
public:
void Drive()
{
cout << "舒适" << endl;
}
};
void Test1()
{
Benz car;
car.Drive(); //舒适
}
组合的应用如下:
//Tire和Car构成has-a 的关系 车有轮胎
class Tire
{
protected:
string _brand = "Michelin"; //品牌
};
class Car
{
protected:
string _colour = "白色"; //颜色
string _num = "陕A123"; //车牌号
Tire _t; //轮胎
};
若创建一个对象 Car _c;
由上面代码看到,这里的Car 组合了Tire, 则通过监视窗口可以看到Tire 变成Car 的一部分。
我暂时就讲到这里啦。有其他更多精彩的内容,我会在之后更新,大家可以多关注我的博客哟~
下篇博客,我会继续讲继承。
继承(四):https://blog.csdn.net/ly_6699/article/details/88858618
讲到复杂的菱形继承和菱形的虚拟继承