此文编写参考狄泰软件学院唐佐林老师的视频课程
一、子类可以直接访问父类的私有成员吗?
1、对于这个问题的两个不同的视角
(1)、根据面向对象的理论,因为子类拥有父类的一切行为何属性,因此应该可以直接访问父类的私有成员。
(2)、根据c++语法本身,因为外界不能够直接访问类的private成员,因此子类不可以访问父类的私有成员。
那么实际情况是怎样的呢?下面通过实验便知。
#include<iostream>
using namespace std;
class Parent
{
private:
int value;
public:
Parent()
{
value=100;
}
int get_value()
{
return value;
}
};
class Child:public Parent
{
public:
int add_Value(int m)
{
value=m+value;//此处是访问了父类的私有成员
}
};
int main()
{
return 0;
}
结果:
运行结果表明了该程序的编写是有错误的,那么原因又是什么呢?具体请看下面内容。
2、三种访问级别
事实上之前的两种视角都是没有错的,这个只是访问级别的问题,在c++中不只只有public和private这两种访问级别,还存在一种叫protected的访问级别,那么proteced的意义是什么呢?
protected的意义:
- 修饰的成员不能够被外界访问
- 修饰的成员可以被子类直接访问
我们可以通过生活中的实例来理解protected的意义,因为c++是面向对象的语言,是可以用程序来描述生活问题的。对于一个公司的女生而言,可能她的身高和体重是不希望被别人知道的,所以这个就可以看成是私有成员,但是她的姓名是大家都知道的,因此可以看成是公有成员,然而对于她在公司里的薪资是保密的,但是她可以告知她的家里人,所以这个私密性就介于公有属性和私有属性之间了,在c++中就是用protected这个关键字来描述问题了。
学了protected这个关键字之后,我们就可以用它来修改一下上面的这个程序了,也就是将上面程序中的父类中的私有属性改成protected。为加深对这三种访问级别,程序修改后如下所示:
#include<iostream>
using namespace std;
class Parent
{
protected:
int value;
public:
Parent()
{
value=100;
}
int get_value()
{
return value;
}
};
class Child:public Parent
{
public:
int add_Value(int m)
{
value=value+m;
}
};
int main()
{
Parent p1;//创建一个父类对象
//p1.value=200;//error,因为这里直接访问value相当是外界直接访问
cout<<"value="<<p1.get_value()<<endl;
Child c1;//创建一个子类对象
//c1.value=200;//error,因为这里直接访问value相当是外界直接访问
cout<<"value="<<c1.get_value()<<endl;//c1继承了父类的属性和行为
c1.add_Value(100);//子类可以直接访问父类的protected成员
cout<<"value="<<c1.get_value()<<endl;//通过这个加法证明是访问成功的
return 0;
}
3、如何选择合适的访问级别
该图中有两个分支,其实逻辑非常简单,首先我们在定义类的时候就应该思考一下,这个类以后是否有可能被继承,当有这个可能的时候,这个时候我们就应该注意了,定义成员的时候,我们希望这个成员能够被外界访问吗,这里的外界是指全局函数或者是与该类没有任何关系的其他类,如果希望能够被访问,那么就定义为public,如果不希望被访问,那么这个时候就要考虑该类希望被以后的子类访问吗,如果希望被子类访问,那么这时就应该定义成protected的访问级别,否则就定义成private的访问级别。
二、组合与继承综合实例
此例要用c++来描述下图中的关系。
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
class Object
{
protected:
//因为是用这两个成员变量来描述问题,所以最终要输出的就是这两个成员变量的信息,因为注定要被继承,所以用protected
string mName;//用来记录名字
string mInfo;//用来记录具体信息
public:
Object()
{
mName="Object";
mInfo="";//初始化为空字符串
}
string name()
{
return mName;//获取名字
}
string info()
{
return mInfo;//获取具体信息
}
};
class Point:public Object//继承
{
private:
int mX;
int mY;
public:
Point(int x=0,int y=0)
{
mX=x;
mY=y;
mName="Point";//直接使用Object的成员变量
ostringstream oss;
oss<<"Point("<<mX<<","<<mY<<")";
mInfo=oss.str();//直接使用Object的成员变量
}
int x()
{
return mX;
}
int y()
{
return mY;
}
};
class Line:public Object//继承Object
{
private:
Point mP1;//与Point构成组合关系,也就是同生死的关系
Point mP2;//与Point构成组合关系,也就是同生死的关系
public:
Line(Point p1,Point p2)
{
mP1=p1;
mP2=p2;
mName="Line";//直接使用Object的成员变量
ostringstream oss;
oss<<"Line from "<<mP1.info()<<" to "<<mP2.info();
mInfo=oss.str();//直接使用Object的成员变量
}
Point begin()
{
return mP1;
}
Point end()
{
return mP2;
}
};
int main()
{
Object o//创建一个实体对象o
Point p1(0,0);
Point p2(8,8);
Line line(p1,p2);//将p1,p2连接成线
//打印信息
cout<<o.name()<<endl;
cout<<o.info()<<endl;
cout<<endl;
cout<<p1.name()<<endl;
cout<<p1.info()<<endl;
cout<<endl;
cout<<p2.name()<<endl;
cout<<p2.info()<<endl;
cout<<endl;
cout<<line.name()<<endl;
cout<<line.info()<<endl;
cout<<endl;
return 0;
}
运行结果:
三、总结
- c++中面向对象的访问级别有private,public,protected
- protected修饰的成员不能够被外界访问
- protected使得子类可以访问父类的成员
- protected这个关键字是专门为了继承而设计的
- 没有protected就没有办法完成真正意义上的代码复用