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 则表示全部主分片都正常运行(集群可以正常服务所有请求),但是 副本 分片没有全部处在正常状态. ...
随机推荐
- 2023年ccpc大学生程序设计竞赛-crf
第一次参加这种大型线下程序设计比赛,心情自然是很激动,但比赛中并没有想象中那么顺利,甚至可以说有些惊险,比赛开始的时候,我们三人随便看看题,顺便等着跟榜,对于签到题我们自然是相信clk可以很快地独立完 ...
- Vue-treeselect 实现下拉树懒加载,末节点不要箭头
项目需要,可选择的下拉树,由于数据过多,显示要有层级感,所以使用了懒加载模式 vue-treeselect官网:https://www.vue-treeselect.cn/ 1.前端代码 1.下载依赖 ...
- C++ 核心指南之 C++ P.哲学/基本理念(上)
C++ 核心指南(C++ Core Guidelines)是由 Bjarne Stroustrup.Herb Sutter 等顶尖 C+ 专家创建的一份 C++ 指南.规则及最佳实践.旨在帮助大家正确 ...
- [golang]jwt生成与解析
前言 golang-jwt是go语言中用来生成和解析jwt的一个第三方库,早先版本也叫jwt-go.本文中使用目前最新的v5版本. 安装 go get -u github.com/golang-jwt ...
- 《Pro Git》Git基础笔记
获取Git仓库 在已存在目录中初始化仓库 $ git init 该命令会创建一个名为.git的隐藏文件. 克隆现有的仓库 $ git clone <url> # 例如 git clone ...
- 《SQL与数据库基础》19. 日志
目录 日志 错误日志 二进制日志 日志格式 日志查看 日志删除 查询日志 慢查询日志 本文以 MySQL 为例 日志 错误日志 错误日志是 MySQL 中最重要的日志之一,它记录了当 mysql 启动 ...
- 发布策略:蓝绿部署、金丝雀发布(灰度发布)、AB测试、滚动发布、红黑部署的概念与区别
蓝绿发布(Blue-Green Deployment) 蓝绿发布提供了一种零宕机的部署方式.不停老版本,部署新版本进行测试,确认OK,将流量切到新版本,然后老版本同时也升级到新版本.始终有两个版本同时 ...
- WPF学习 - 自定义Panel
WPF中的Panel(面板),是继承自FrameworkElement的抽象类,表示一个可以用来排列子元素的面板. 在WPF中,一种预设了几种常用的面板,如Grid.StackPanel.WrapPa ...
- QA|如何给我们的自动化测试代码增加日志记录?|Loguru
这里我们用的是loguru,logging虽然是自带的,但确实使用起来比较繁琐,loguru在Logging基础上增加了很多个性化功能,使用起来也比较简单,所以就使用loguru 代码如下: 1 # ...
- docker搭建CMS靶场
项目地址:https://github.com/Betsy0/CMSVulSource 该项目是为了方便在对CMS漏洞进行复现的时候花费大量的时间在网上搜索漏洞源码,从而有了此项目.此项目仅为安全研究 ...