当前课程知识点:C++语言程序设计进阶 > 第七章 继承与派生 > 继承方式 > 继承方式简介及公有继承
派生类成员对基类成员的访问权限
通过派生类对象对基类成员的访问权限
公有继承
私有继承
保护继承
继承的访问控制
基类的public和protected成员:访问属性在派生类中保持不变;
基类的private成员:不可直接访问。
访问权限
派生类中的成员函数:可以直接访问基类中的public和protected成员,但不能直接访问基类的private成员;
通过派生类的对象:只能访问public成员。
Point.h
#ifndef _POINT_H #define _POINT_H class Point { //基类Point类的定义 public: //公有函数成员 void initPoint(float x = 0, float y = 0){ this->x = x; this->y = y; } void move(float offX, float offY){ x += offX; y += offY; } float getX() const { return x; } float getY() const { return y; } private: //私有数据成员 float x, y; }; #endif //_POINT_H
Rectangle.h
#ifndef _RECTANGLE_H #define _RECTANGLE_H #include "Point.h" class Rectangle: public Point { //派生类定义部分 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; } private: //新增私有数据成员 float w, h; }; #endif //_RECTANGLE_H
main.cpp
#include <iostream> #include <cmath> using namespace std; #include “Rectangle.h” int main() { Rectangle rect; //定义Rectangle类的对象 //设置矩形的数据 rect.initRectangle(2, 3, 20, 10); rect.move(3,2); //移动矩形位置 cout << "The data of rect(x,y,w,h): " << endl; //输出矩形的特征参数 cout << rect.getX() <<", " << rect.getY() << ", " << rect.getW() << ", " << rect.getH() << endl; return 0; }
大家好
欢迎回来继续学习
C++语言程序设计
这一节呢
我们来学习继承方式
我相信大家已经急不可耐了
在前面的
类的继承的语法中呢
大家看到
继承每个基类都有个继承方式
那继承方式到底是什么呢
接下来我们就来看
继承方式的问题
为什么要区分不同的继承方式呢
不同的继承方式
它的差别在什么地方呢
主要是两个方面
一个是
在派生类的内部
派生类的成员
它怎么去访问基类
继承过来的成员
能访问哪些
不能访问哪些
另一个方面就是说
在派生类和基类之外
这个类的派生家族
之外的某个地方
构造一个派生类的对象
然后通过派生类的对象
去调用从基类
继承过来的成员函数
去访问
从基类继承过来的数据成员
那这个时候
它能访问吗
不同的继承方式
在这两个方面
就反映出它的不同了
那么到底有哪些
不同的继承方式呢
在C++中
继承方式一共有三种
一个是公有继承
一个是私有继承
还有一个
介于它们两个中间
叫做保护继承
公有继承呢
实际上是最宽泛的一种继承
也是我们写程序中
最常用的一种继承
尤其是初学的同学们
你就尽量用公有继承就行了
为什么呢
一会你就看到了
公有继承
它是基类里面的public
和protected成员
它继承过来以后
在派生类中
它的访问控制属性
都保持不变
所以原来public还是public
原来的protected还是protected
但是
注意啊
这个private成员
它就不能直接访问了
这个大家可以理解吗
私有的嘛
我们人有时候继承遗产的时候
某个遗产还附加一个条件的
不是说这个遗产给你
你就直接可以用了
我附加什么条件才能给你
对吧
我们人类社会有这样的情况
那程序中呢
也给你留了这样一种途径
那么私有成员呢
到了派生类中
派生类的成员函数
就不能直接访问
从基类继承过来的私有成员
那你说这私有成员
有什么用啊
继承过来光占地还不能用
不是
你要用也可以
一般来说
我们的类为私有成员
都提供了公有的访问接口
所以只要基类
提供了公有访问接口
那派生类的成员
可以通过公有访问接口
也就是有条件地去使用
基类继承过来的私有成员
那么这项规定有什么用呢
其实是非常有用的
我们知道基类
可能是另外一个团队开发的
可能是随着软件包
带来的这种类库
那么我们派生类的编写者是谁呢
是我们现在
比如说
我们这个应用程序的开发者
我拿那个类库来以后
有一些类可以用
我把它继承过来
那里面的私有成员
当然应该不可直接访问
为什么呢
因为我都不知道它是什么
不让我直接访问它最好
对吧
那么派生类中的成员函数
可以访问基类的公有和保护成员
但是不能访问私有成员
这就是一个规则
那么通过派生类的对象呢
从类外只能访问公有成员
这个跟原来学过的规则是一样的
下面呢
我就来给大家演示一个
公有继承的例子
在这个例题中呢
我们看定义了一个点类
point类
定义了一个矩形类
用公有方式继承了点类
然后在主函数中
我们要定义一个矩形类的对象
观察一下
通过这个对象
去调用的这些成员函数
都是哪个类定义的函数
好 现在我们通过单步执行
跟踪进去
进到这个主函数里面
构造了一个矩形对象
所以这个时候呢
我们看到对象里面
构造完了以后
没有含有有意义的数据
是垃圾数据
因为在有继承的情况下呢
写构造函数
要关注的因素比较多
所以在这个例题中
不管是点类
还是矩形类中
我们都没有显示的定义构造函数
那就由编译器在需要的时候
为我们隐含生成默认的构造函数
那这个隐含生成的默认构造函数
因为它是不进行
任何实质性的初始化工作的
所以构造完以后
这个矩形的对象呢
它没有一个确定的初始值
因此呢
我们还是需要对这个对象
进行一下初始化
这个初始化呢
我们就写了一个
普通的成员函数initRectangle
来进行这个初始化
当然这个函数
它是不会被自动调用的
所以大家看到
在程序中呢
我们要主动的显示着
去调用这个函数
把初始参数列进来
列到参数表里面
这个初始参数呢
前两个我们希望用来
作为点的坐标
后两个呢作为宽和高
也就是说
前两个是表示矩形的位置
后两个表示矩形的宽和高
那我们来看这个
进到这个rectangle
它的initRectangle函数以后
会怎么样执行
好 那么我们再按f11
追踪到这个函数里面
现在进来了
这个函数是要初始化这个矩形
但是呢
只有宽和高
是矩形类自己新增定义的
另外
这个矩形的位置
是继承了这个点类
也就是说
这个矩形的位置x y坐标
是它基类的私有成员
所以在这个rectangle类的函数中
是不直接访问的
怎么办呢
基类中定义有
这种公有接口函数
initPoint
我们可以调用这个函数
来对x y进行初始化
所以这里呢
我们调用initPoint
我们看到进到initPoint里面来
执行完了以后
然后再对本类的宽和高赋值
这样就完成了点的初始化
回到主函数中
我们看到点现在有值了
大家看
它里面内嵌了一个point对象
坐标是我们给它的2和3
然后宽和高是20和10
接下来再移动矩形的位置
通过rect这个对象
去调用move函数
但是我们看rectangle这个类里面
并没有写move函数
但是呢
point类里有个move函数
这个move就被继承到
rectangle里面了
并且它原来是公有的
rectangle用公用方式继承point
所以继承过来
它依然是公有的
现在我们可以在主函数中
去直接调用它
看看进到哪个函数里面了
进到point类的move函数里面了
执行完了以后
回到主函数
接下来呢
我们来调用
这些get函数
首先
我们来看
进到了getH里面
把H值取回来
再往下走呢
我们进到getW里面
把W值取回来
再往下走
我们看进到了getY里面
这是基类point类定义的
公有函数成员
说明它确实被继承到了
tangle里面
而且依然是公有的
所以我们才可以在类外
通过对象调用它
再次追踪
进到了getX函数里面
好
这些get函数都执行完了以后
就接下来会继续完成
我们要执行的这个输出
执行完了输出以后
我们来看这个输出结果在这儿
执行完了输出以后
那么程序到return这儿结束
所以通过这个例子
我们可以看到
基类的公有成员继承过来
用公有方式继承过来
都是公有的
基类的私有成员
用公有方式继承过来
在派生类的成员函数中
是不能直接访问的
要调用它的公有接口访问
然后在类外定义
派生类的对象的时候
可以通过派生类的对象
去访问
派生类自己定义的公有函数
也可以访问
从公有基类继承过来的
原有的公有成员函数
继承过来
仍然是公有 仍然是public
-导学
--导学
-继承的基本概念和语法
-第七章 继承与派生--继承的基本概念和语法习题
-继承方式
-第七章 继承与派生--继承方式
-基类与派生类类型转换
-第七章 继承与派生--基类与派生类类型转换
-派生类的构造和析构
--派生类的构造函数
--派生类的析构函数
--第七章 继承与派生--派生类的构造和析构
-派生类成员的标识与访问
--虚基类
-第七章 继承与派生--派生类成员的标识与访问
-小结
--小结
-综合实例
--第七章综合实例
-实验七
--实验七
-导学
--导学
-第八章 多态性--导学
-运算符重载
--运算符重载的规则
-第八章 多态性--运算符重载
-虚函数
--虚函数
--虚析构函数
--虚表与动态绑定
-第八章 多态性--虚函数
-抽象类
--抽象类
--第八章 多态性--抽象类
-override与final
-第八章 多态性--override与final
-小结
--第八章小结
-综合实例
--第八章综合实例
-实验八
--实验八
- 第八章讲义
-导学
--导学
-模板
--函数模板
--类模板
-第九章 模板与群体数据--模板
-线性群体
--线性群体的概念
-第九章 模板与群体数据--线性群体
-数组
--数组类模板
-链表
--链表类模板
-第九章 模板与群体数据--链表
-栈
--栈类模板
--栈类模板课后习题
--例9-9 栈的应用课后习题
-队列
--队列类模板
-第九章 模板与群体数据--队列
-排序
--排序概述
--插入排序
--选择排序
--交换排序
-第九章 模板与群体数据--排序
-查找
--查找
--查找课后习题
-小结
--小结
-综合实例
--综合实例
-实验九
--实验九
- 第九章讲义
-导学
--导学
-泛型程序设计及STL的结构
--STL简介
-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构
-迭代器
--迭代器
-第十章 泛型程序设计与C++标准模板库--迭代器
-容器的基本功能与分类
-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类
-顺序容器
--顺序容器的特征
--第十章 泛型程序设计与C++标准模板库--顺序容器
-关联容器
--集合
--映射
-第十章 泛型程序设计与C++标准模板库--关联容器
-函数对象
--函数对象
--函数适配器
-算法
--算法
-小结
--第十章小结
-综合实例
--综合实例
-实验十
--实验十
- 第十章讲义
-导学
--导学
-I/O流的概念及流类库结构
-第十一章 流类库与输入/输出--I/O流的概念及流类库结构
-输出流
--输出流概述
--向文本文件输出
--向二进制文件输出
--向字符串输出
-第十一章 流类库与输入/输出--输出流
-输入流
--输入流概述
--输入流应用举例
--从字符串输入
-第十一章 流类库与输入/输出--输入流
-输入/输出流
--输入/输出流
-第十一章 流类库与输入/输出--输入/输出流
-小结
--小结
-综合实例
--综合实例
-实验十一
--实验十一
- 第十一章讲义
-导学
--第12章导学
-异常处理的思想与程序实现
-第十二章 异常处理--异常处理的思想与程序实现
-异常处理中的构造与析构
-第十二章 异常处理--异常处理中的构造与析构
-标准程序库异常处理
-第十二章 异常处理--标准程序库异常处理
-小结
--第12章小结
-综合实例
--综合实例
-实验十二
--实验十二
- 第十二章讲义