上一篇学习了继承的基础概念以及示例代码。算是对继承有了一个简单的了解。如果想要对继承有更深的了解,就要复习访问权限的知识点。这样才能深化对继承的了解,以及学习不同的继承方式能对哪些数据进行操作。
类成员包括数据成员和函数成员,分别描述问题的属性和行为,是不可分割的两个方面。对类成员访问权限的控制,是通过设置成员的访问控制属性来实现的。访问控制属性有:公有类型、私有类型和保护类型。这里简单的说一下不同类型的作用。公有类型成员定义了类的接口。私有成员只能被本类的成员函数和友元函数访问,来自类外部的任何访问都是非法的。这样,私有成员就完全隐藏在类中,保护了数据的安全性。保护类型成员的性质和私有成员的性质相似,其差别在于继承过程中对派生类影响不同。
#include <iostream>
using namespace std;
class Asd
{
public:
int x;
Asd(int a = 0, int b = 0, int c = 0);
int getx(){return x;}
int gety(){return y;}
void sety1(int b){y = b;}
int getz(){return z;}
void setz1(int c){z = c;}
void sety2(int b){protectedsety(b);}
void setz2(int c){privatesetz(c);}
void print()
{
cout << "X:" << x << " " << "Y:" << y << " " << "Z:" << z <<endl;
}
protected:
int y;
void protectedsety(int b){y = b;}
private:
void privatesetz(int c){z = c;}
int z;
};
Asd::Asd(int a, int b, int c)
{
x = a;
y = b;
z = c;
}
int main()
{
Asd a(3, 2, 3);
a.print(); //通过print()函数打印
a.sety1(3); //通过public中的函数设置y
a.setz1(4); //通过public中的函数设置z
a.print();
a.sety2(4); //由protected中的函数设置y
a.setz2(5); //由private中的函数设置z
cout << "(x,y,z):";
cout << "(" << a.getx() << "," << a.gety() << "," << a.getz() << ")" <<endl; //由public中的函数得到数据
cout << "X:" << a.x <<endl; //正确,对象可以直接访问公有数据
//cout << "Y:" << a.y <<endl; //错误,对象不能直接访问保护数据
//cout << "Z:" << a.z <<endl; //错误,对象不能直接访问私有数据
//a.protectedsety(1); //错误,对象不能直接访问保护成员函数
//a.privateserz(1); //错误,对象不能直接访问私有成员函数
return 0;
}
在这个示例代码中,每种类型都有数据成员和函数成员。可以清楚的看到public中的函数是如何充当接口的。在这个类中,可以通过public中的函数直接设置y、z的值,也可以通过public中的函数去访问protected和private中的函数,最终达到设置y、z值的目的。在public中的数据成员可以通过”对象名.数据成员”的方式直接使用,而其他类型的数据成员则不行。
公有继承:
#include <iostream>
using namespace std;
class Point
{
private:
float x;
float y;
float findx()const{return x;}
protected:
void setz(int a){z = a;}
float z;
public:
void initPoint(float x = 0, float y = 0, float z = 0)
{
this->x = x;
this->y = y;
this->z = z;
}
Point(){}
Point(float r)
{
x = r;
}
void move(float a, float b)
{
x += a;
y += b;
}
float getx()const{return x;}
float gety()const{return y;}
float getz()const{return z;}
float getprivatex()const{return findx();}
};
class Rectangle:public Point
{
private:
float w,h;
public:
void initRectangle(float x, float y, float w, float h)
{
initPoint(x,y);
this->w = w;
this->h = h;
}
float geth()const{return h;}
float getw()const{return w;}
//float publicgetx1()const{return getx();} //正确,getx()是基类公有成员函数
//float publicgetx2()const{return findx();} //错误,findx()是基类中的私有成员函数
float publicgetx3()const{return getprivatex();} //正确,getprivatex()是基类公有成员函数
void publicsetz(int a){setz(a);} //正确
};
int main()
{
Rectangle rect;
rect.initRectangle(2,3,10,10);
rect.move(3,2);
cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
cout << "X:" << rect.publicgetx3() <<endl;
rect.publicsetz(20);
cout << "Z:" << rect.getz() <<endl;
//rect.setz(1); //错误,派生类对象不能直接访问基类保护成员函数
//rect.findx(); //错误,派生类对象不能直接访问基类私有成员函数
return 0;
}
(1)基类的private、public、protected成员的访问属性在派生类中保持不变。
(2)派生类中继承的成员函数可以直接访问基类中所有成员,派生类中新增的成员函数只能访问基类的public和protected成员,不能访问基类的private成员。
在上述代码中,基类中的move(),getx(),gety()都被派生类继承了,而且move(),getx()&gety()在基类中就是public中的函数。由(1)可知,派生类对象可以直接使用这些函数。由派生类中新增的三个publicgetx()函数可知,派生类新增函数能访问public成员,不能访问private成员。由publicsetz()可知,派生类新增函数能访问protected成员。若想让派生类中的新增成员函数访问private成员,可以通过基类中public中的函数间接的访问基类的private成员(如:publicgetx3()函数)。可以这样做,但一般不会这样做,因为在做项目的时候是不会动基类的。
(3)通过派生类的对象只能访问基类的public成员。(rect.setz(1)和rect.findx()报错的原因是它们不是基类public的成员函数)
保护继承:
#include <iostream>
using namespace std;
class Point
{
private:
float x;
float y;
float findx()const{return x;}
protected:
void setz(int a){z = a;}
float z;
public:
void initPoint(float x = 0, float y = 0, float z = 0)
{
this->x = x;
this->y = y;
this->z = z;
}
Point(){}
Point(float r)
{
x = r;
}
void move(float a, float b)
{
x += a;
y += b;
}
float getx()const{return x;}
float gety()const{return y;}
float getz()const{return z;}
float getprivatex()const{return findx();}
};
class Rectangle:protected Point
{
private:
float w,h;
public:
void initRectangle(float x, float y, float w, float h)
{
initPoint(x,y);
//setz(10); //派生类可以访问基类保护成员函数
this->w = w;
this->h = h;
}
void move(float a, float b){Point::move(a,b);} //与public继承的不同
float getx()const{return Point::getx();} //与public继承的不同
float gety()const{return Point::gety();} //与public继承的不同
float getz()const{return Point::getz();} //与public继承的不同
float geth()const{return h;}
float getw()const{return w;}
//float publicgetx1()const{return getx();} //正确,getx()是基类公有成员函数
//float publicgetx2()const{return findx();} //错误,findx()是基类中的私有成员函数
float publicgetx3()const{return getprivatex();} //正确,getprivatex()是基类公有成员函数
void publicsetz(int a){setz(a);} //正确
};
int main()
{
Rectangle rect;
rect.initRectangle(2,3,10,10);
rect.move(3,2);
cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
cout << "X:" << rect.publicgetx3() <<endl;
rect.publicsetz(20);
cout << "Z:" << rect.getz() <<endl;
//rect.setz(1); //错误,派生类对象不能直接访问基类保护成员函数
//rect.findx(); //错误,派生类对象不能直接访问基类私有成员函数
return 0;
}
(1)基类的public、protected成员都以protected身份出现在派生类中。
(2)派生类中新增的成员函数可以直接访问基类中的public和protected成员,但不能访问基类的private成员。
由(1)可知,基类的public成员都以protected身份出现在派生类中,所以派生类的对象不能像公有继承那样直接使用基类中public的函数。而是要根据需求添加成员函数。例如:
void initRectangle(float x, float y, float w, float h)
{
initPoint(x,y);
this->w = w;
this->h = h;
}
void move(float a, float b){Point::move(a,b);} //与public继承的不同
float getx()const{return Point::getx();} //与public继承的不同
float gety()const{return Point::gety();} //与public继承的不同
float getz()const{return Point::getz();} //与public继承的不同
因为派生类中新增的成员函数可以直接访问基类中的public和protected成员,而且在派生类中没有initPoint()的同名函数,所以在initRectangle()函数中可以直接使用initPoint()函数,而不需要写成Point::initPoint();。如果派生类对象要使用getx()函数,那么就要在派生类public中定义:
方法一:指明getx()的来历
float getx()const{return Point::getx();}。
方法二:为了避免重名可以写成:
float protectedgetx()const{return getx();}。
(3)通过派生类的对象不能访问基类的任何成员。(因为继承来的成员以protected身份出现在派生类中)
私有继承:
#include <iostream>
using namespace std;
class Point
{
private:
float x;
float y;
float findx()const{return x;}
protected:
void setz(int a){z = a;}
float z;
public:
void initPoint(float x = 0, float y = 0, float z = 0)
{
this->x = x;
this->y = y;
this->z = z;
}
Point(){}
Point(float r)
{
x = r;
}
void move(float a, float b)
{
x += a;
y += b;
}
float getx()const{return x;}
float gety()const{return y;}
float getz()const{return z;}
float getprivatex()const{return findx();}
};
class Rectangle:private Point
{
private:
float w,h;
public:
void initRectangle(float x, float y, float w, float h)
{
initPoint(x,y);
this->w = w;
this->h = h;
}
void move(float a, float b){Point::move(a,b);} //与public继承的不同
float getx()const{return Point::getx();} //与public继承的不同
float gety()const{return Point::gety();} //与public继承的不同
float getz()const{return Point::getz();} //与public继承的不同
float geth()const{return h;}
float getw()const{return w;}
//float publicgetx1()const{return getx();} //正确,getx()是基类公有成员函数
//float publicgetx2()const{return findx();} //错误,findx()是基类中的私有成员函数
float publicgetx3()const{return getprivatex();} //正确,getprivatex()是基类公有成员函数
void publicsetz(int a){setz(a);}
};
int main()
{
Rectangle rect;
rect.initRectangle(2,3,10,10);
rect.move(3,2);
cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
cout << "X:" << rect.publicgetx3() <<endl;
rect.publicsetz(20);
cout << "Z:" << rect.getz() <<endl;
//rect.setz(1); //错误,派生类对象不能直接访问基类保护成员函数
//rect.findx(); //错误,派生类对象不能直接访问基类私有成员函数
return 0;
}
(1)基类的public、protected成员都以private身份出现在派生类中。(与保护继承的不同)
(2)派生类中新增的成员函数可以直接访问基类中的public和protected成员,但不能访问基类的private成员。(这里和保护继承的情况是一样的)
(3)通过派生类的对象不能访问基类的任何成员。(因为继承来的成员以private身份出现在派生类中)。可以和上述保护继承一样,通过新增成员函数让对象使用基类的一些操作。
数据成员和函数成员在继承过程中以相应继承方式出现在派生类中的情况可以这样理解:
注意:private和protected之间的区别只有在基类派生的类中才能表现出来。派生类的成员可以直接访问基类的保护成员,但不能直接访问基类的私有成员。因此,对外而言,保护成员的行为与私有成员相似;对内而言,保护成员的行为与公有成员相似。
在上述的代码中,私有继承和保护继承的区别可能不是很明显。要想了解的更深,我们可以在Rectangle类的基础上再派生新的类,在新的派生类中看不同的继承方式对类中各成员的影响。
保护继承后再公有继承:
#include <iostream>
using namespace std;
class Point
{
private:
float x;
float y;
float findx()const{return x;}
protected:
void setz(int a){z = a;}
float z;
public:
void initPoint(float x = 0, float y = 0, float z = 0)
{
this->x = x;
this->y = y;
this->z = z;
}
Point(){}
Point(float r)
{
x = r;
}
void move(float a, float b)
{
x += a;
y += b;
}
float getx()const{return x;}
float gety()const{return y;}
float getz()const{return z;}
float getprivatex()const{return findx();}
};
class Rectangle:protected Point
{
private:
float w,h;
public:
void initRectangle(float x, float y, float w, float h)
{
initPoint(x,y);
//setz(10); //派生类可以访问保护成员函数
this->w = w;
this->h = h;
}
void move(float a, float b){Point::move(a,b);} //与public继承的不同
float getx()const{return Point::getx();} //与public继承的不同
float gety()const{return Point::gety();} //与public继承的不同
float getz()const{return Point::getz();} //与public继承的不同
float geth()const{return h;}
float getw()const{return w;}
//float publicgetx1()const{return getx();} //正确,getx()是基类公有成员函数
//float publicgetx2()const{return findx();} //错误,findx()是基类中的私有成员函数
float publicgetx3()const{return getprivatex();} //正确,getprivatex()是基类公有成员函数
void publicsetz(int a){setz(a);}
};
class A:public Rectangle
{
private:
float a;
public:
void initA(float x)
{
initRectangle(1,2,3,4);
a = x;
setz(20); //正确,setz()是Point类的protected成员
}
//float getx()const{return Rectangle::getx();} //正确
float getx()const{return Point::getx();} //正确
};
int main()
{
Rectangle rect;
rect.initRectangle(2,3,10,10);
rect.move(3,2);
cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
cout << "X:" << rect.publicgetx3() <<endl;
rect.publicsetz(20);
cout << "Z:" << rect.getz() <<endl;
//rect.setz(1); //错误,派生类对象不能直接访问基类保护成员函数
//rect.findx(); //错误,派生类对象不能直接访问基类私有成员函数
A a;
a.initA(10);
cout << "A.getx():" << a.getx() <<endl;
return 0;
}
因为Rectangle类是保护继承,Point类的public、protected成员都以protected身份出现在派生类中,而A是公有继承的(基类各属性保持不变),所以在A类中新增成员函数可以使用setz()函数。而且在定义A类中getx()函数时,以下两种形式都是正确的。(改变class A的继承方式,上面的程序都能正常运行)原因是保护继承后再公有继承,A类仍然可以访问到Point类的成员。
float getx()const{return Rectangle::getx();}
float getx()const{return Point::getx();}
私有继承后再公有继承:
#include <iostream>
using namespace std;
class Point
{
private:
float x;
float y;
float findx()const{return x;}
protected:
void setz(int a){z = a;}
float z;
public:
void initPoint(float x = 0, float y = 0, float z = 0)
{
this->x = x;
this->y = y;
this->z = z;
}
Point(){}
Point(float r)
{
x = r;
}
void move(float a, float b)
{
x += a;
y += b;
}
float getx()const{return x;}
float gety()const{return y;}
float getz()const{return z;}
float getprivatex()const{return findx();}
};
class Rectangle:private Point
{
private:
float w,h;
public:
void initRectangle(float x, float y, float w, float h)
{
initPoint(x,y);
this->w = w;
this->h = h;
}
void move(float a, float b){Point::move(a,b);} //与public继承的不同
float getx()const{return Point::getx();} //与public继承的不同
float gety()const{return Point::gety();} //与public继承的不同
float getz()const{return Point::getz();} //与public继承的不同
float geth()const{return h;}
float getw()const{return w;}
//float publicgetx1()const{return getx();} //正确,getx()是基类公有成员函数
//float publicgetx2()const{return findx();} //错误,findx()是基类中的私有成员函数
float publicgetx3()const{return getprivatex();} //正确,getprivatex()是基类公有成员函数
void publicsetz(int a){setz(a);}
};
class A:public Rectangle
{
private:
float a;
public:
void initA(float x)
{
initRectangle(1,2,3,4);
a = x;
//setz(20); //报错,因为setz()是Point的保护成员
}
float getx()const{return Rectangle::getx();} //正确
//float getx()const{return Point::getx();} //错误,不能访问Point类的getx()
};
int main()
{
Rectangle rect;
rect.initRectangle(2,3,10,10);
rect.move(3,2);
cout << rect.getx() << " " << rect.gety() << " " <<rect.getw() << " " << rect.geth() <<endl;
cout << "X:" << rect.publicgetx3() <<endl;
rect.publicsetz(20);
cout << "Z:" << rect.getz() <<endl;
//rect.setz(1); //错误,派生类对象不能直接访问基类保护成员函数
//rect.findx(); //错误,派生类对象不能直接访问基类私有成员函数
A a;
a.initA(10);
cout << "A.getx():" << a.getx() <<endl;
return 0;
}
上述代码可以这样理解:
结合上面两个代码和图片可以看出私有继承与保护继承的区别。①因为Rectangle私有继承后,基类的public、protected成员都以private身份出现在派生类中。而setz()函数是Point类中的保护成员(相当于第三种情况),在Rectangle中是私有成员,所以A类中不能访问setz()函数(A的新增成员函数只能访问私有继承的Rectangle中的A2,B2,但是setz()相当于是B1)。②Rectangle类中的getx()函数在public中,A类中的新增成员函数能访问到(Rectangle的getx()相当于是A2),所以float getx()const{return Rectangle::getx();}是正确的。由于Rectangle私有继承Point,所以A访问不到Point类的getx()函数(Point类的getx()相当于是A1),所以float getx()const{return Point::getx();}是错误的,换句话说就是私有继承后再公有继承的派生类访问不到上上个基类的成员。以上两点就是公有继承与私有继承的区别。
文章浏览阅读240次。河北农业大学2010-2011学年现科C语言考试试题及答案河北农业大学课程考试试卷2010—2011学年第2学期 2010 级 独立学院 专业 卷别:A考试科目: C语言程序设计 考核方式: 闭卷考试姓 名: 学号: 专业班级:(注:考生务必将答案写在答题纸上,写在本试卷上无效)本试卷共( 3 )页选择题(共30分,每题1..._河北农业大学c语言程序设计答案
文章浏览阅读1.2k次。2743:字符串判等查看提交统计提示提问总时间限制: 1000ms 内存限制: 65536kB描述字符串的相关比较 strcmp strlen 最后为了容易比较 在字符串后加上 '\0' 代表字符串的结束判断两个由大小写字母和空格组成的字符串在忽略大小写,且忽略空格后是否相等。输入两行,每行包含一个字符串。输出若两个字符串_字符串判等 查看提交统计提问 总时间限制: 1000ms 内存限制: 65536kb 描述
文章浏览阅读1k次。原因是app设置了:if (@available(iOS 11, *)) { UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; }解决方案 :在弹出系统相册前添加 if (@available(iOS 11, *)) { UIScr..._ios wkwebview打开相册 照片上移
文章浏览阅读1.8k次。EChartsECharts是什么?下面是来自官方的介绍:ECharts,缩写来自Enterprise Charts,商业级数据图表,一个纯Javascript的图表库,可以流畅的运行在PC和移动设备上,兼容当前绝大部分浏览器(IE6/7/8/9/10/11,chrome,firefox,Safari等),底层依赖轻量级的Canvas类库ZRender,提供直观,生动,可交互,可高度个性化定制的数..._pyecharts添加鼠标绘制工具线
文章浏览阅读8.2k次,点赞8次,收藏30次。计算机网络应用层课后习题练习(一)计算机网络应用层课后习题练习(二)应用层知识点概览课后习题练习(二)应用层知识点概览课后习题练习(二)6-17在浏览 器中应当有几个可选解释程序。试给出一些可选解释程序的名称。HTML解释器,java解释器HTML解释器必备,有某些java小程序需要用到java解释器6-18 - 一个万维网网点有1000万个页面,平均每个页面有10个超链。读取- -..._6-40用asn.1基本编码规则对以下4个数组(sequence-of)进行编码。假定每一个数字占
文章浏览阅读2.8k次。正在学习Android,想先找个简单点的东西练习一下,先想到的是通讯录,不过关于手机通讯录方面的资料在我现有的书和视频上都很少看到。没办法只有自己看SDK Docs了。 不管怎么说还是先赞Google的Android Docs,确实很全面,只要你想找就一定能找到你要的东西。不过我感觉想把里面的各个类的关系联系起来还是有点困难,特别是像英文水平过于一般的我,看的那叫个累呀。 好了,还是来说一下正题吧。Android刚开始在通讯录方面好像是提供的Contact_kotlin 通讯录 查询
文章浏览阅读3.2k次。流瞬ElectroMagneticWorks(EMWorks).EMS.2017.SP1.4.for.SW2011-2018.Win64三维电磁场仿真软件 EMS帮助设计人员计算的电、磁、机械和热参数包括力、转矩、磁通密度、磁场、电场、电流、流、涡流、电感、电容、电阻、磁链、损耗、饱和,感应电压,力密度,功率损耗,温度、温度梯度、热通量和更。EMS是一种基于强大的有限元方法的三维电磁场仿真_emworks
文章浏览阅读537次。这里的continue的意思是在内存上continue,正常情况下,头一行的末尾在内存里和下一行的开头是相连的,但是有时候我们做了一些操作,选取了Mat 的一部分,例如选了一个ROI 这时候就不满足上面说的相连了。那么这时候continuous就被判定为假。..._mat n_iscontinuous
文章浏览阅读2.1k次。android 8.0,9.0系统锁屏流程分析_android timeout锁屏流程 源码
文章浏览阅读1.2w次。使用中标麒麟文件共享Samba功能,主要用的是开始菜单里的连接到服务器,或者文件浏览器里的访问服务器功能!!!文件共享实施手册(仅供参考)中标麒麟系列OS访问windows上的共享文件夹(SMB)1.开启win上的Samba共享服务(控制面板-程序-启用或关闭windows功能,如图1)2.设置文件夹共享2.1(右击文件夹-属性-共享,添加访问的用户名,没有可以新建,新建的时候跳过邮箱登陆即可,如图2。选择Everyone要配置好相应的权限及设置图5相关选项)2.2点击高级共享选项,设置._中标麒麟访问windows共享
文章浏览阅读502次。那么书接上回,今天主要是继续探究React Native与原生模块的架构方式。原生模块原生模块可以访问activity、运行环境、GPS、存储空间等。原生模块就是能够在JavaScript层调用的API。因为对原生模块的全部请求都要异步执行。如果原生方法需要为JavaScript层的调用返回数据,该操作将通过promise或者回调函数来完成。React Native为这两种方式都提供了..._reactnative 安卓constantstoexport
文章浏览阅读1.6k次,点赞2次,收藏4次。安卓系统:ios系统:可以看出:对于汉字 => 安卓和ios的区分是一样的,只有normal和bold。但是注意一点,ios的加粗是从600往后开始算的,安卓的是从700开始算的。所以我们日常要是给文字加粗,正常就是写font-weight:bold/700;对于字母和数字 => 安卓是有对于不同数值的粗细区分的,但是ios没有,跟汉字一样只有normal和bold。另外,lighter只针对安卓有效果,相当于是100/200的粗细效果。normal统一都是400,bold是700_安卓能识别的字体粗细font-weight: bold;