C++学习 之 继承(笔记)
1.继承基础:
继承就像是生物里的遗传与变异,即派生类(子代)从基类(父代)那里继承基类的某些特性(遗传),并在此基础上拥有自己的特性(变异)。
C++派生语法:
class Base//定义一个基类
{
//...基类成员
};
class Derived:access-specifier Base//定义一个派生类
{
//...派生类成员
}
其中access-specifier可以是public、private、protected(表示派生类有一个基类)。
以下程序清单从Fish类派生出了Carp和Tuna类的一种简单的继承层次结构:
#include<iostream>
using namespace std;
class Fish //定义Fish类
{
public:
bool FreshWaterFish; void Swim()
{
if (FreshWaterFish)
cout << "Swims in lake" << endl;
else
cout << "Swims in sea" << endl;
}
}; class Tuna :public Fish//定义Tuna类,将继承的Fish类的成员或方法作为自己的public成员或方法
{
public:
Tuna()
{
FreshWaterFish = false;
}
}; class Carp :public Fish
{
public:
Carp()
{
FreshWaterFish = true;
}
}; int main()
{
Carp myLunch;
Tuna myDinner; cout << "Getting my food to swim" << endl; cout << "Lunch:";
myLunch.Swim(); cout << "Dinner:";
myDinner.Swim(); return ;
}
2.向基类传递参数:
向基类传递参数在初始化派生类对象时有的时候显得很有用。比如上面的Fish类派生出Carp类和Tuna类,可以修改成如下代码:
#include<iostream>
using namespace std;
class Fish
{
protected:
bool FreshWaterFish;
Fish(bool IsFreshWater)
{
FreshWaterFish = IsFreshWater;
}
public:
void Swim()
{
if (FreshWaterFish)
cout << "Swims in lake" << endl;
else
cout << "Swims in sea" << endl;
return;
}
}; class Tuna :public Fish
{
public:
Tuna():Fish(false) {}//派生类每次定义对象都指出是淡水鱼还是咸水鱼,采用参数列表将bool值传递给基类的构造函数
}; class Carp :public Fish
{
public:
Carp():Fish(true) {}
}; int main()
{
Carp myLunch;
Tuna myDinner; cout << "Getting my food to swim" << endl; cout << "Lunch:";
myLunch.Swim(); cout << "Dinner:";
myDinner.Swim(); return ;
}
3.在派生类中覆盖基类的方法:
如果派生类中有和基类中的函数名相同,返回值和特征标也相同时,就相当于派生类的方法覆盖了基类的方法。我们还拿Fish类,Tuna类和Carp类来举例子。
用Tuna和Carp类的Swim()覆盖Fish类的Swim():
#include<iostream>
using namespace std;
class Fish
{
protected:
bool FreshWaterFish;
Fish(bool IsFreshWater)
{
FreshWaterFish = IsFreshWater;
}
public:
void Swim()
{
if (FreshWaterFish)
cout << "Swims in lake" << endl;
else
cout << "Swims in sea" << endl;
return;
}
}; class Tuna :public Fish
{
public:
Tuna():Fish(false) {}
void Swim()//此函数与基类函数在调用上效果相同,基类函数被覆盖
{
cout << "Tuna swim fast" << endl;
}
}; class Carp :public Fish
{
public:
Carp():Fish(true) {}
void Swim()
{
cout << "Carp swim low" << endl;
}
}; int main()
{
Carp myLunch;
Tuna myDinner; cout << "Getting my food to swim" << endl; cout << "Lunch:";
myLunch.Swim(); cout << "Dinner:";
myDinner.Swim(); return ;
}
上面的程序的结果显示了,在主函数中对象调用方法Swim()时调用的并不是Fish类里的方法了,而是Tuna和Carp自己的方法,这样基类的方法就相当于是被覆盖了。覆盖是的派生类的方法可以自定 义,但如果我们还想使用基类的方法,就必须想办法使得机器可以知道我们调用的Swim()的作用域在哪个范围。
4. 调用基类中被覆盖的方法:
上面说到了我们只需要让机器知道我们调用的Swim()的作用域,就可以使得被覆盖的基类方法重新被调用。我们可以在调用基类方法时使用"::"作用域解析运算符。
以上面的调用Swim()的代码为例:
myLunch.Swim();//调用派生类Carp中的Swim()
my.Lunch.Fish::Swim();//调用基类Fish中的Swim()
如果基类的方法没有被覆盖,则可以在派生类中和调用函数一样来调用基类的方法。如果被覆盖的话就要使用"::"作用域解析运算符。在主函数里调用就是类似语句:"my.Lunch.Fish::Swim();"在派 生类调用基类被覆盖方法时类似于语句:"Fish::Swim"。
5. 在派生类中隐藏基类的方法:
覆盖的一种极端情形就是,Tuna::Swim()可能隐藏Fish::Swim()的所有重载版本,使得使用这些重载版本会导致编译错误。
以下面代码为例:
#include<iostream>
using namespace std;
class Fish
{
public:
void Swim()
{
cout << "Fish swims...!" << endl;
}
void Swim(bool FreshWaterFish)
{
if (FreshWaterFish)
cout << "Swims in lake" << endl;
else
cout << "Swims in sea" << endl;
return;
}
}; class Tuna :public Fish
{
public:
void Swim()
{
cout << "Tuna swim fast" << endl;
}
};
int main()
{
Tuna myDinner; cout << "Getting my food to swim" << endl;
cout << "Dinner:";
myDinner.Swim();
//myDinner.Swim(false); return ;
}
代码在6-17行实现了基类方法Swim的重载,在23-26行实现了派生类方法Swim对基类方法Swim的覆盖。观察发现派生类里只有一个版本的Swim方法,Fish中的Swim的重载版本Swim(bool)版本好像是没 有被覆盖,但其实Swim(bool)也类似被覆盖的情况是没法在派生类或主函数中像调用其他函数那样被调用的。如果我们去掉35行的注释符号,代码就会有编译错误,这也说明了问题。以上说明了在派生类 中覆盖基类的方法时是与函数的参数无关的,只要函数名称,返回值,特征值相同就会被覆盖。
调用基类中被隐藏的方法:
解决方案1:在main函数中使用作用域解析运算符"::"。
myDinner.Fish::Swim();
解决方案2:在派生类中使用关键字using解除对基类方法的隐藏。
class Tuna:public Fish
{
public:
using Fish Swim;//解除对Fish::Swim()重载版本的隐藏,其中不包括与派生类参数也相同的方法。
void Swim(){}
}
解决方案3:在Tuna类中重新定义所有Fish类的被覆盖的方法的重载版本。
C++学习 之 继承(笔记)的更多相关文章
- Python学习的个人笔记(基础语法)
Python学习的个人笔记 题外话: 我是一个大二的计算机系的学生,这份python学习个人笔记是趁寒假这一周在慕课网,w3cschool,还有借鉴了一些博客,资料整理出来的,用于自己方便的时候查阅, ...
- hadoop2.5.2学习及实践笔记(四)—— namenode启动过程源码概览
对namenode启动时的相关操作及相关类有一个大体了解,后续深入研究时,再对本文进行补充 >实现类 HDFS启动脚本为$HADOOP_HOME/sbin/start-dfs.sh,查看star ...
- hadoop2.5.2学习及实践笔记(二)—— 编译源代码及导入源码至eclipse
生产环境中hadoop一般会选择64位版本,官方下载的hadoop安装包中的native库是32位的,因此运行64位版本时,需要自己编译64位的native库,并替换掉自带native库. 源码包下的 ...
- 开始记录学习java的笔记
今天开始记录学习java的笔记,加油
- 菜鸟教程之学习Shell script笔记(上)
菜鸟教程之学习Shell script笔记 以下内容是,学习菜鸟shell教程整理的笔记 菜鸟教程之shell教程:http://www.runoob.com/linux/linux-shell.ht ...
- Exception类的学习与继承总结
日期:2018.11.11 星期日 博客期:023 Exception类的学习与继承总结 说起来我们上课还是说过的!老师提到了报错问题出现主要分Exception和Error两类!第一次遇见这个问题是 ...
- 深度学习Keras框架笔记之AutoEncoder类
深度学习Keras框架笔记之AutoEncoder类使用笔记 keras.layers.core.AutoEncoder(encoder, decoder,output_reconstruction= ...
- 深度学习Keras框架笔记之TimeDistributedDense类
深度学习Keras框架笔记之TimeDistributedDense类使用方法笔记 例: keras.layers.core.TimeDistributedDense(output_dim,init= ...
- 深度学习Keras框架笔记之Dense类(标准的一维全连接层)
深度学习Keras框架笔记之Dense类(标准的一维全连接层) 例: keras.layers.core.Dense(output_dim,init='glorot_uniform', activat ...
- Elasticsearch7.X 入门学习第九课笔记-----聚合分析Aggregation
原文:Elasticsearch7.X 入门学习第九课笔记-----聚合分析Aggregation 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. ...
随机推荐
- 22.Python赋值运算符(入门必读)
赋值运算符主要用来为变量(或常量)赋值,在使用时,既可以直接用基本赋值运算符“=”将右侧的值赋给左侧的变量,右侧也可以在进行某些运算后再赋值给左侧的变量. = 基本赋值运算符 Python 使用“=” ...
- 记一次sparkOnyarn错误:java.lang.UnsatisfiedLinkError
错误大概这样: Caused by: java.util.concurrent.ExecutionException: Boxed Error Caused by: java.lang.Unsatis ...
- Linux sssd 进程 ldap 客户端配置
Linux sssd 进程 ldap 客户端配置 标签(空格分隔): ldap authconfig authconfig命令解析:authconfig 面对多计算机的身份管理以及账户信息同步, 其解 ...
- Pycharm查看源代码的问题
linear = torch.nn.Linear() # 无法查看Linear的源代码 from torch.nn import Linear linear = Linear() # 可以查看Line ...
- DMA数据传输
从字面意思上看,DMA即为“直接内存读取”的意思,换句话说DMA就是用来传输数据的,它也属于一个外设.只是在传输数据时,无需占用CPU. 高速IO设备可以在处理器安排下直接与主存储器成批交换数据,称为 ...
- Spring常用的jar+普通构造注入
常用工具 jar 说明 提供AOP(面向切面编程)实现:spring -aop spring提供对AspectJ框架的整合:spring-aspects 提供 IoC(控制反转)的基础实现:sprin ...
- JVM 监控工具——jstack
[参考文章]:jstack 命令使用经验总结 1. 简介 jstack主要用于生成java虚拟机当前时刻的线程快照. 线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合, 主要目的是定位 ...
- OUC_Summer Training_ DIV2_#4之数据结构
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26100#problem/A A - A Time Limit:1000MS Me ...
- TCP输出 之 tcp_transmit_skb
概述 tcp_transmit_skb的作用是复制或者拷贝skb,构造skb中的tcp首部,并将调用网络层的发送函数发送skb:在发送前,首先需要克隆或者复制skb,因为在成功发送到网络设备之后,sk ...
- Java操作符——i++ 和 ++i的区别
问题:前置自增和后置自增的区别 Code-后置自增 public class Test { public static void main(String[] args) { int a = 2; in ...