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版权协议,转载请附上原文出处链接和本声明. ...
随机推荐
- 第06课:作用域、JS预解析机制
从字面上理解----域就是空间.范围.区域,作用就是读.写,所以作用域我们可以简单理解为:在什么样空间或者范围内对数据进行什么样的读或写操作. 看一下代码 alert(a); // 为什么是undef ...
- 2017多校联合训练2—HDU6054--Is Derek lying?(思维题)
Is Derek lying? Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)T ...
- ansible主机互信
前文讲了ansible,但是ansible是基于ssh来做的,首先的和管理主机之间做主机互信,简单来说主机互信就是把主机上产生的公钥传到互信主机上就可以了. 在主机上产生公钥文件.使用命令:ssh-k ...
- JS将后台获取毫秒数转换为自定义格式日期
重写prototype Date.prototype.Format = function(fmt) { var o = { "M+" : this.getMonth()+1, / ...
- 转发:Java对象及其引用
原文: http://zwmf.iteye.com/blog/1738574 Java对象及其引用 关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知 ...
- Tag 标签
用于标记和选择. 基础用法 由type属性来选择tag的类型,也可以通过color属性来自定义背景色. <el-tag>标签一</el-tag> <el-tag type ...
- 手动部署 OpenStack Rocky 双节点
目录 文章目录 目录 前言 OpenStack 架构 Conceptual architecture Logical architecture 网络选型 Networking Option 1: Pr ...
- Selenium 2自动化测试实战23(窗口截图)
一.窗口截图 WebDriver提供了截图函数get_screenshot_as_file()来截取当前窗口. # -*- coding: utf-8 -*- from selenium import ...
- (转)MongoDB 分片集群技术
1.1 MongoDB复制集简介 一组Mongodb复制集,就是一组mongod进程,这些进程维护同一个数据集合.复制集提供了数据冗余和高等级的可靠性,这是生产部署的基础. 1.1.1 复制集的目的 ...
- style属性
style加样式是加在行间,取样式也是在行间取: 我们来看下面这段代码: <!DOCTYPE HTML> <html> <head> <meta charse ...