22.C++- 继承与组合,protected访问级别
在C++里,通过继承和组合实现了代码复用,使得开发效率提高,并且能够通过代码看到事物的关系
组合比继承简单,所以在写代码时先考虑能否组合,再来考虑继承.
组合的特点
- 将其它类的对象作为当前类的成员使用
比如主机类,拥有 CPU/主板/内存/硬盘这4个对象成员,而这4个对象成员并没有继承主机类的特性和行为
继承的特点
- 新的类(子类)具有旧的类(父类)的属性和行为
- 旧的类被称为父类,也叫基类
- 新的类被称为子类,也叫派生类(一个派生类也可以继承多个基类)
- 子类可以添加新的属性和行为(成员变量和成员函数),也可以重写已有的属性和行为
- 一个子类只继承一个父类,便被称为单继承
- 一个子类若继承多个父类,便被称为多继承
- 子类其实就是一个特殊的父类,比如:苹果手机是手机,就是将苹果手机当做一个特殊的父类对待
子类对象可以初始化父类对象,也可以赋值给父类对象,比如:
class Parent { int mValue; public: Parent() { mValue=10; } int Value() { return mValue; } }; class Child : public Parent { public: Child() { cout<<"I'm child"<<endl; } }; int main() { Child c;
cout<< c.Value() <<endl; //调用父类的成员函数 Parent p1 =c; //通过子类初始化父类 Parent p2; p2=c; //通过子类复制给父类 }
类的访问级别之protected
大家都知道,类里private修饰的成员和函数,不能被外界直接访问.
虽然子类拥有父类的属性和行为,但是在子类里,也不能访问父类的private私有成员
比如:
class Parent { int mValue; public: Parent(int i=0) { mValue=i; } int Value() { return mValue; } }; class Child : public Parent { public: Child() { cout<<mValue<<endl; //在子类中,访问父类的private成员,将会编译报错 } };
所以类的访问级别引入了新的关键字protected
protected的特性
- 修饰的成员不能被外界直接访问
- 修饰的成员可以被子类(包括子类的子类)直接访问, 也可以在本类内部直接访问
有了protected的加入,定义类时,我们就需要仔细考虑成员的访问级别,如下图所示:
接下来做个综合实例,组合与继承
- 需要一个父类Object, 为子类Point和子类Line 提供name名字和info信息
- 由于线Line至少需要两个点Point才能组成,所以Line子类内部需要通过Point子类来组合
如下图所示:
开始写代码:
#include <iostream> #include <string> #include <sstream> using namespace std; class Object { protected: string mName; string mInfo; public: Object() { mName="Object"; mInfo=""; } string name() { return mName; } string info() { return mInfo; } }; class Point : public Object { protected: int x; //坐标 int y; public: Point(int x=0,int y=0) { ostringstream s; this->x =x; this->y =y; s<<"P("<<x<<","<<y<<")"; //坐标信息 mName="Point"; mInfo=s.str(); } }; class Line : public Object { private: Point mP1; Point mP2; public: Line(Point p1,Point p2) { ostringstream s; mP1 =p1; mP2 =p2; s<<"Line from " <<p1.info() <<" to "<<p2.info(); //线的信息 mName ="Line"; mInfo =s.str(); } }; int main() { Point p1(2,3); Point p2(6,3); Line L(p1,p2);
/*打印点的信息*/ cout<<p1.name()<<":"<<endl; cout<<p1.info()<<endl; /*打印线的信息*/ cout<<L.name()<<":"<<endl; cout<<L.info()<<endl; return 0; }
运行打印:
Point: P(2,3) Line: Line from P(2,3) to P(6,3)
接下来来学习: 23.C++- 继承的多种方式、显示调用父类构造函数、父子之间的同名函数、虚函数
人间有真情,人间有真爱。