前言

上一篇学习了继承的基础概念以及示例代码。算是对继承有了一个简单的了解。如果想要对继承有更深的了解,就要复习访问权限的知识点。这样才能深化对继承的了解,以及学习不同的继承方式能对哪些数据进行操作。

类成员包括数据成员和函数成员,分别描述问题的属性和行为,是不可分割的两个方面。对类成员访问权限的控制,是通过设置成员的访问控制属性来实现的。访问控制属性有:公有类型、私有类型和保护类型。这里简单的说一下不同类型的作用。公有类型成员定义了类的接口。私有成员只能被本类的成员函数和友元函数访问,来自类外部的任何访问都是非法的。这样,私有成员就完全隐藏在类中,保护了数据的安全性。保护类型成员的性质和私有成员的性质相似,其差别在于继承过程中对派生类影响不同。

类中public、protected和private数据成员、函数成员的使用:

#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中的函数设置ya.setz1(4);                 //通过public中的函数设置za.print();a.sety2(4);                 //由protected中的函数设置ya.setz2(5);                 //由private中的函数设置zcout << "(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();}是错误的,换句话说就是私有继承后再公有继承的派生类访问不到上上个基类的成员。以上两点就是公有继承与私有继承的区别。

C++学习笔记:(六)public、protected、private继承详解相关推荐

  1. C++ (public, protected, private继承)

    http://thinkinginmylife.spaces.live.com/blog/cns!E44140D5E07BEC07!137.entry 我转~~~C++5(public, protec ...

  2. 【相机标定与三维重建原理及实现】学习笔记1——相机模型数学推导详解

    目录 前言 一.小孔成像模型 二.坐标系的变换 1.世界坐标系到相机坐标系的变换(刚体变换)[xw^→xc^\boldsymbol {\hat{x_{w}}}\rightarrow \boldsymb ...

  3. SNMP学习笔记之SNMP 原理与实战详解

    原文地址:http://freeloda.blog.51cto.com/2033581/1306743 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  4. RT-Thread学习笔记|TCS34725 RGB 颜色识别传感器详解

    rt-thread是什么? RT-Thread 是一个集实时操作系统(RTOS)内核.中间件组件和开发者社区于一体的技术平台,组件完整丰富.高度可伸缩.简易开发.超低功耗.高安全性的物联网操作系统.R ...

  5. ios学习笔记3--导航控制器详解

    前言: 导航控制器和标签控制器是ios中常用的两个控件.因此,特意写一篇文章记录一下,自己对导航控制器的理解,持续更新中. 导航条UINavigationBar介绍 容器UINavigationIte ...

  6. HTML学习笔记3:HTML基本骨架详解

    在HTML笔记1中,我简单介绍了HTML抽象的基本框架,其实,HTML的基本骨架部分还有更多内容需要了解,这一节,咱们就详细学习HTML的基本骨架. 打开sublime编辑器,输入html:xt 图1 ...

  7. Storm学习笔记(三)——Storm组件详解之Bolt、Topology

    目录 Bolt消息处理者 生命周期 开发Bolt组件 Topology拓扑 结构 运行模式 示例 Bolt消息处理者 Bolt在Storm中是一个被动的角色,它把元组作为输入,然后产生新的元组作为输出 ...

  8. pytorch学习笔记(十二):详解 Module 类

    Module 是 pytorch 提供的一个基类,每次我们要 搭建 自己的神经网络的时候都要继承这个类,继承这个类会使得我们 搭建网络的过程变得异常简单. 本文主要关注 Module 类的内部是怎么样 ...

  9. 吴恩达深度学习笔记(114)-RNN梯度消失问题详解

    https://www.toutiao.com/a6652968074712449550/ 2019-02-10 14:34:53 循环神经网络的梯度消失(Vanishing gradients wi ...

最新文章

  1. 冰箱温度调到这个数值,就能节省超过35万吨食物
  2. ThreadLocal的使用及原理分析
  3. Dubbo的设计理念原来就藏在这三张图中
  4. python爬虫从入门到放弃(九)之 实例爬取上海高级人民法院网开庭公告数据
  5. 软件“美不美”,UI测试一下就知道
  6. html基础技术笔记
  7. python打包和添加数据文件_使用pyinstaller 2.1将python打包并添加版本信息和图标
  8. 软件测试管理的基本要素
  9. git切换到旧版本_git如何更新到指定版本,然后再更新到最新版本
  10. 新概念英语(第三册,新版)学习(原文及全文翻译)
  11. 阿里云企业邮箱标准版多域名绑定
  12. linux 备份信息查看器,linux 全新的备份神器 Duplicity
  13. 锁升级过程(偏向锁/轻量级锁/重量级锁)
  14. 最短路径之Bellman-Ford
  15. 啃光学论文的笔记(1)
  16. MySQL配置参数大全
  17. 区块链需要学习哪些东西_学习区块链需要哪些 这些基础知识要知道
  18. freeBSD的VNET_DEFINE跟SYSCTL_VNET_INT
  19. 【人工智能实验】卷积神经网络CNN框架的实现与应用-手写数字识别
  20. 【英语系列一】—量变到质变亲体验

热门文章

  1. VC批量拷贝,移动,删除文件---SHFileOperation
  2. Android OpenSL ES 对象结构
  3. Linux 基础I/O :文件描述符,重定向,文件系统,软链接和硬链接,动态库和静态库
  4. spring源码构建以及模块划分和依赖
  5. 使用VMware VSphere WebService SDK进行开发 (六)——检测告警信息
  6. 【今晚七点半】:5G时代的云游戏还缺什么?
  7. 计算机网络常见问题总结
  8. [Android]Linux下WebRTC下载与编译
  9. 为什么虚拟机的linux系统IP是10.0.2.15
  10. 从Google Mesa到百度PALO(数仓)