C++基础杂记(3)
类的继承
基类与派生类之间的构造行为
派生类可以调用基类的公共成员,但无法调用基类的私有成员。所以派生类无法直接初始化基类中的私有成员变量。在派生类中初始化基类的私有成员变量需要显式的调用基类的构造函数,并以委托构造的方式将其初始化。
// 基类头文件 basic.h
#ifndef __BASIC__
#define __BASIC__
class Basic
{
private:
int basic_pri_val;
void basicPriFuc() const;
public:
Basic(int _pri_val, int _pub_val):basic_pri_val(_pri_val), basic_pub_val(_pub_val){}
int basic_pub_val;
void basicPubFuc() const;
void showBasicPriVal() const;
};
#endif
// 基类源文件 basic.cpp
#include <iostream>
#include "basic.h"
using std::cout;
void Basic::basicPriFuc() const
{
cout<< "Basic private function.\n";
}
void Basic::basicPubFuc() const
{
cout<< "Baisc public function.\n";
}
void Basic::showBasicPriVal() const
{
cout<< "Basic private value: "<< basic_pri_val<< '\n';
}
// 派生类头文件 derive.h
#ifndef __DERIVE__
#define __DERIVE__
#include "basic.h"
class Derive:public Basic // 从 Basic 类派生
{
public:
Derive(int _basic_pri_val, int _basic_pub_val):Basic(_basic_pri_val, _basic_pub_val){} // 委托基类构造函数初始化基类成员变量
};
#endif
// 派生类源文件 derive.cpp
#include "derive.h"
// 主程序源文件 main.cpp
#include "derive.h"
int main()
{
Derive derive = {1, 2};
// derive.basicPriFuc(); // 不可访问基类私有成员函数
derive.basicPubFuc(); // 可以访问基类公共成员函数
// derive.basic_pri_val; // 不可访问基类私有成员变量
derive.showBasicPriVal(); // 基类私有成员变量可以通过基类公共成员函数访问
derive.basic_pub_val; // 可以访问基类公共成员变量
return 0;
}
Baisc public function.
Basic private value: 1
另外,基类的引用或指针可以指向派生类,但这样的引用和指针只能调用来自于基类的方法。
在派生类中使用基类方法
在派生类中使用基类方法只需要在方法前加上域解析运算符,如下:
// 假定类 Basic 中已经定义了 myPrint 方法
class Derive:: public Basic
{
public:
void myPrint()
{
Basic::myPrint(); // 调用类 Basic 中的 myPrint 方法
myPrint(); // 调用类 Derive 中的 myPrint 方法
}
}
protected 的访问权限
对于类外而言,protected 的访问权限与 private 相似。对于派生类而言, protected 的访问权限与 public 相似。
多态公有继承
在进行本节之前需要知道:父类的指针/引用可以指向/引用派生类,但只能调用继承于父类的方法或重写在子类中的虚方法。
多态有静态多态和动态多态两个部分。
- 静态多态相当于在派生类中重写了(不是重载)父类中的函数,函数的声明中,形参类型和数量可以与父类不一致。派生类只能调用重写后的函数,而不能够再使用被重写的父类中的函数。
- 动态多态发生在使用父类指针或引用,调用或重写修函数时。下面将进行详细的演示。
关键字 virtual
- 只有类的非静态成员函数可以成为虚函数,其他非类成员函数或类的静态成员函数不行。
- 类中的虚函数,即使不被调用也必须被定义。而非虚函数在不被调用的情况下可以只声明不定义。
- 派生类与父类中的虚函数声明必须完全一致,包括函数名与形参类型。
- virtual 还可用于类的虚继承。
使用 virtual 修饰类的成员函数,其成员函数的调用行为只在下列情况下不同:
- 对于一般的成员函数,如果使用类的指针或者引用来调用该函数,则函数的行为将取决于声明该指针/引用的类型。即如果是父类类型的的指针/引用,则将调用父类中的函数;如果是派生类类型的指针/引用,则将调用派生类中的函数。
- 对于虚成员函数,如果使用类的指针或引用来调用该函数,则函数的行为取决于指针所指向的对象的类型。
示例
// 基类头文件 basic.h
#ifndef __BASIC__
#define __BASIC__
class Basic
{
private:
int basic_pri_val;
void basicPriFuc() const;
public:
Basic(int _pri_val, int _pub_val):basic_pri_val(_pri_val), basic_pub_val(_pub_val){}
// virtual ~Basic() {}; // 在包含虚函数时,应当包含一个虚析构函数
int basic_pub_val;
void basicPubFuc() const;
void showBasicPriVal() const;
void myPrint() const; // 非虚函数,下面将在派生类中重写
};
#endif
// 基类源文件 basic.cpp
#include <iostream>
#include "basic.h"
using std::cout;
void Basic::basicPriFuc() const
{
cout<< "Basic private function.\n";
}
void Basic::basicPubFuc() const
{
cout<< "Baisc public function.\n";
}
void Basic::showBasicPriVal() const
{
cout<< "Basic private value: "<< basic_pri_val<< '\n';
}
void Basic::myPrint() const
{
cout<< "Basic class print.\n";
}
// 派生类头文件 derive.h
#ifndef __DERIVE__
#define __DERIVE__
#include "basic.h"
class Derive:public Basic // 从 Basic 类派生
{
public:
Derive(int _basic_pri_val, int _basic_pub_val):Basic(_basic_pri_val, _basic_pub_val){} // 委托基类构造函数初始化基类成员变量
void myPrint(); // 重写父类中的非虚函数
};
#endif
// 派生类源文件 derive.cpp
#include "derive.h"
using std::cout;
void Derive::myPrint() const
{
cout<< "Derive class print.\n";
}
// 主程序源文件 main.cpp
#include "derive.h"
int main()
{
Derive derive = {1, 2};
Basic & basic = derive;
basic.myPrint();
return 0;
}
Basic class print.
当重写父类中的普通函数时,即使父类引用引用了派生类,但是该引用调用的却是父类中的函数。myPrint 函数的行为却决于引用类型。
如果我们在声明中为 myPrint() 函数加上 virtual 修饰,则程序结果为:
Derive class print
可以看到,myPrint() 函数的行为取决于引用所指向的类。
如果需要在派生类中重定义基类中的方法,则应尽量将该方法声明为虚。且需要在基类中声明一个虚析构函数。
当类被用作基类时,它的虚构函数应当被设置为虚函数,否则将会对派生类对象的内存释放造成麻烦。
抽象基类(ABC)
类中包含纯虚函数的类被称为抽象基类。纯虚函数的声明如下:
class ABC
{
public:
virtual void myPrint() const = 0;
}
纯虚函数可以在抽象基类中被定义。抽象基类的派生类必须使用重写虚函数的方法来重写纯虚函数。抽象基类强制派生类实现其纯虚函数。
私有继承和保护继承
- 在私有继承中,基类的公有成员和保护成员都将成为派生类的私有成员。
- 在保护继承中,基类的公有成员和保护成员都将成为派生类的保护成员。
多重继承
class Deriver : public Basic1, private Basic2 {···};
C++基础杂记(3)的更多相关文章
- java复习(2)---java基础杂记
java命名规范: 参考:http://www.cnblogs.com/maowang1991/archive/2013/06/29/3162366.html 1.项目名小写 2.包名小写 3.类名每 ...
- Webpack系列-第一篇基础杂记
前言 公司的前端项目基本都是用Webpack来做工程化的,而Webpack虽然只是一个工具,但内部涉及到非常多的知识,之前一直靠CV来解决问题,之知其然不知其所以然,希望这次能整理一下相关的知识点. ...
- python基础杂记
一.编码 1.ACSII 0000 0001 8位 一个字节 2. uncoide ...
- .Net基础杂记
1.面向对象程序思想 面向对象是程序开发的一种机制,特征为封装.继承.多态.以面向对象方式编写程序时,将复杂的项目抽象为多个对象互相协作的模型,然后编写模型结构,声明或实现类型的成员,即描述对象的特征 ...
- Webpack系列-第三篇流程杂记
系列文章 Webpack系列-第一篇基础杂记 Webpack系列-第二篇插件机制杂记 Webpack系列-第三篇流程杂记 前言 本文章个人理解, 只是为了理清webpack流程, 没有关注内部过多细节 ...
- webpack-插件机制杂记
系列文章 Webpack系列-第一篇基础杂记 webpack系列-插件机制杂记 前言 webpack本身并不难,他所完成的各种复杂炫酷的功能都依赖于他的插件机制.或许我们在日常的开发需求中并不需要自己 ...
- 5天揭秘js高级技术-第一天
一.基础杂记 1. document.write() <script type="text/javascript"> document.write('<h2> ...
- 面试基础知识集合(python、计算机网络、操作系统、数据结构、数据库等杂记)
python python _.__.__xx__之间的差别 python中range.xrange和randrange的区别 python中 =.copy.deepcopy的差别 python 继承 ...
- java基础(杂记)
java基础夯实(杂记):1:创建实例对象可以通过无参的构造函数然后调用成员变量去初始化属性,也可以自己定义有参构造方法直接初始化属性,当属性为private时我们可以通过getset方法间接访问:2 ...
- elasticsearch基础知识杂记
日常工作中用到的ES相关基础知识和总结.不足之处请指正,会持续更新. 1.集群的健康状况为 yellow 则表示全部主分片都正常运行(集群可以正常服务所有请求),但是 副本 分片没有全部处在正常状态. ...
随机推荐
- 最为常用的Laravel操作(1)-Eloquent模型
快速入门 更换表名 protected $table = 'my_flights'; 更换主键名称 protected $primaryKey = 'id'; 注意: Eloquent 默认主键字段是 ...
- 不要再傻傻分不清 hash、 chunkhash 和 contenthash 啦
hash.contenthash 和 chunkhash 是通过散列函数处理之后,生成的一串字符,可用于区分文件. 文件名不带哈希值 webpack.config.js 文件中,output 中定义输 ...
- 一文了解react中定义样式(css/less/sass)的常用方法
react中通过jsx的语法方式,将html标签和js语法联系在一起,而css的编写方式,没有明确的指定编写方式,目前就有很多不同方法,每个方式各有其优缺点,我们一起来看看常用的定义方式有哪些. 最基 ...
- Ehcache的Maven依赖及其配置文件
Ehcache的Maven依赖 <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> ...
- LVS专访阿里云席明贤,从视频云2.0到“数能生智”的超长畅谈
这是一篇人物专访,源自LiveVideoStack与阿里云视频云负责人席明贤(花名右贤)的对话.面对风云变幻的内外环境,阿里云在视频云赛道是坚定向前的,右贤没有回避多媒体当下行业面临的困难以及业务面临 ...
- Kurator,你的分布式云原生解决方案
本文分享自华为云社区<DTSE Tech Talk | 第40期:Kurator,你的分布式云原生解决方案>,作者:华为云社区精选. 什么是分布式云原生? 中国信通院给出的定义:分布式云原 ...
- 优化Redis缓存淘汰机制解决性能测试中报错率逐渐攀升问题
在某个查询场景的性能测试过程中,遇到了一个问题:测试过程中报错率逐渐攀升.进一步检查后发现,在查询业务所在应用的后台日志和平台应用的后台日志中,都出现了用户登录相关的报错信息.经过排查分析,发现了问题 ...
- Kafka入门学习
什么是 Kafka Kafka 是由 Linkedin 公司开发的,它是一个分布式的,支持多分区.多副本,基于 Zookeeper 的分布式消息流平台,它同时也是一款开源的基于发布订阅模式的消息引擎系 ...
- 一篇关于获得拼多多商品详情 API的使用说明
拼多多(Pinduoduo)是中国一家快速发展的电商平台,为了帮助开发者更好地接入拼多多,平台提供了丰富的 API 接口供开发者使用,其中包括获取拼多多商品详情的 API.接下来,我们将介绍如何使用拼 ...
- 关于MySQL获取自增ID的几种方法
1. Select Max(id) From Table; 通过取表字段最大值的方式来获取最近一次自增id 缺点: 这种方法在多人操作数据库的软件上不可靠, 举个例子, 你刚插入一条记录. 当你在查询 ...