C++ 抽象机制

抽象机制

1. 虚函数 使用关键字virtual 声明的函数,意思是可能随后在其派生类中重新定义。

纯虚函数 在声明的末尾使用=0 的函数,说明是纯虚函数。

抽象类 含有纯虚函数多的类称为抽象类(abstract class).

多态类型 如果一个类负责为其他一些类提供接口,前面一个类被称为多态类型。

虚函数是如何解析到正确的执行函数呢?

采用的是虚函数表vtbl:
一般编译器将虚函数的名字转换成函数指针表中对应的索引值

class Vector {
private:double* elem;int sz;
public:Vector(int s) : elem{new double[s]}, sz{s} {}~Vector() {delete [] elem;};double& operator[](int i) {return elem[i];}int size() const {return sz;}};
class EmplyClass {};
class Container {// Vector v;
public:void function() {}
};class VirtualContainer{// Vector v;
public:virtual ~VirtualContainer(){}virtual void virtualFunction() = 0;
};class SubContainer : public VirtualContainer {
public:virtual ~SubContainer(){}void virtualFunction() override {}
};class SubContainer2 : public Container {};
int main(int argc, char **argv) {SubContainer con;SubContainer2 con2;EmplyClass c;std::cout << "SubContainer size: " <<sizeof(con)/sizeof(char) <<  std::endl;std::cout << "SubContainer2 size: " <<sizeof(con2)/sizeof(char) <<  std::endl;std::cout << "EmplyClass size: " <<sizeof(c) <<  std::endl;std::cout << "Version " << chapter3_VERSION_MAJOR << "." << chapter3_VERSION_MINOR << std::endl;return 0;
}

运行结果为:

SubContainer size: 8
SubContainer2 size: 1
EmplyClass size: 1
Version 0.1

对于con(SubContainer) , 继承自类VirtualContainer(抽象类), 存在一个vtbl 指针,如下图:
在64位操作系统中指针占8个byte.

在这里插入图片描述

对于con2(SubContainer2), 继承自Container(非抽象类),其中没有, 如下图:
占用1个byte.

而对于一个空的类型EmptyClass 对象, 如下图:
占用1byte.

在这里插入图片描述

  • What is empty class ?
    Empty class: It is a class that does not contain any data members (e.g. int a, float b, char c, and string d, etc.) However, an empty class may contain member functions.
    对于继承自非抽象类的子类和一个空实体类,占用1个byte. Why is the Size of an Empty Class Not Zero in C++?

When the structure was introduced in C, there was no concept of Objects at that time. So, according to the C standard, it was decided to keep the size of the empty structure to zero.

In C++, the Size of an empty structure/class is one byte as to call a function at least empty structure/class should have some size (minimum 1 byte is required ) i.e. one byte to make them distinguishable.

  • 如果类包含虚函数,则该类的对象需要一个额外的指针;另外对于这样的类需要一个vtbl.

基类的析构函数

如果基类不提供析构函数,或者析构函数不是虚函数, 在使用抽象基类的接口操纵时,子类的析构函数会无法访问;
如果基类的析构函数是虚函数,则子类的析构函数会覆盖它。当使用基类的接口操纵派生类时,才能确保调用到正确的析构函数。

class VirtualContainer{// Vector v;
public:/*(1)*/virtual ~VirtualContainer() {std::cout << "VirtualContainer release: " <<  std::endl;}// virtual ~VirtualContainer(){}virtual void virtualFunction() = 0;
};
class SubContainer : public VirtualContainer {
public:~SubContainer() {std::cout<< "SubContainner release" << std::endl;}
// virtual ~SubContainer(){}void virtualFunction() override {}
};// 当以如下方式使用时:VirtualContainer* baseContainer = new SubContainer();delete baseContainer;// 在此处析构 baseContainer 时, 如果没有(1) 的声明,~SubContainer() 将不会被调用

拷贝和移动

  • 默认情况下,拷贝的默认含义是逐成员复制。 逐成员复制通常符合拷贝操作的本来语义,对于像vector 或者抽象类型 是不正确的。

拷贝容器

类对象的拷贝操作可以通过两个成员来定义:拷贝构造函数和拷贝复制函数

Vector(const Vector& a); // 拷贝构造函数
Vector& operator=(const Vector& a); // 拷贝运算符Vector::Vector(const Vector& a):elem(new double[sz]),sz(a.sz)
{for (int i = 0; i < a.sz; i++) {elem[i] = a.elem[i];}
}Vector& Vector::operator=(const Vector& a) {double *p = new double[a.sz];for (int i = 0; i < a.sz; i++) {p[i] = a.elem[i];}delete[] elem;elem = p;sz = a.sz;return *this;
}

移动容器

  • 对于大的容器而言,拷贝过程耗费巨大(可能是时间或者空间上的耗费)
 声明:/** 移动构造函数*/Vector(Vector&& a);/** 移动赋值运算符*/Vector& operator=(Vector&& a);
实现:
Vector::Vector(Vector&& a):elem(a.elem),sz(a.sz)
{std::cout << "移动构造函数被调用" << std::endl;a.elem = nullptr;a.sz = 0;
}Vector& Vector::operator=(Vector&& a) {std::cout << "移动赋值运算符被调用" << std::endl;if (this != &a) {this->elem = a.elem;this->sz = a.sz;}a.elem = nullptr;a.sz = 0;return *this;
}
  • 左值: 能出现在赋值运算符的左侧的内容
  • 右值: 无法为其赋值的值
  • && 右值引用
  • 移动构造函数不接受(const实参, 因为移动构造函数会删除实参中的值,如果放了const 则无法删除)
  • 使用移动构造函数或拷贝构造的场合

资源管理

  • 可以把指针转化为资源句柄,比如使用智能指针(如unique_ptr)实现强资源安全,对于一般概念上的资源可以消除资源泄漏。

抑制操作

虽然类中可能未定义拷贝构造或者移动构造函数等,但是当代码中存在拷贝或者移动的操作情况下,编译器会自动生成相应的构造函数或者赋值函数。
对于部分实现类,使用默认的拷贝构造函数或移动操作常常意味着风险。对于不需要或者不能移动或者复制的类,最好是删除默认的拷贝和移动操作。

形式大致如下:

Shape(const Shape&) = delete;  // 没有拷贝操作
Shape& operator=(const Shape&) = delete;Shape(Shape&& ) = delete;  // 没有移动操作
Shape& operator=(Shape&& )= delete;

模板

  • 模板: 一个模板(template)就是一个类或一个函数,但是需要我们用一组类型或者值对其进行参数化。
  • 使用模板表示那些通用的概念,通过指定实参,生成特定的类型或者函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/5706.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

unity入门——按钮点击了却无法调用函数

查阅了一番都没有解决问题&#xff0c;最后发现问题是由button的Onclick()事件绑定了代码脚本而不是游戏对象导致的。 如果Onclick()事件绑定的是代码脚本&#xff0c;则下拉框里没有函数&#xff0c;但是点击MonoScript后能手动填入函数名&#xff08;本以为这样就能实现调用…

State.initState() must be a void method without an `async` keyword错误解析

文章目录 报错问题报错的代码 错误原因解决方法解析 另外的方法 报错问题 State.initState() must be a void method without an async keyword如下图&#xff1a; 报错的代码 报错的代码如下&#xff1a; overridevoid initState() async{super.initState();await getConf…

openssl3.2 - exp - 使用默认的函数宏,在release版中也会引入__FILE__

文章目录 openssl3.2 - exp - 使用默认的函数宏&#xff0c;在release版中也会引入__FILE__概述笔记验证是否__FILE__在release版下也能用&#xff1f;将openssl编译成release版的&#xff0c;看看CRYPTO_free()是否只需要一个参数就行&#xff1f;将工程中的openssl相关的库换…

重定义大语言模型的记忆能力:对抗性压缩如何挑战现有测量法

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; Rethinking LLM Memorization through the Lens of Adversarial Compression 引言&#xff1a;探索大型语言模型的记忆能力 在当今信息时代&#xff0c;大型…

Window(Qt/Vs)软件添加版本信息

Window&#xff08;Qt/Vs&#xff09;软件添加版本信息 文章目录 Window&#xff08;Qt/Vs&#xff09;软件添加版本信息VS添加版本信息添加资源文件添加版本定义头自动更新版本添加批处理脚本设置生成事件 Qt添加版本信息添加资源文件文件信息修改自动更新版本 CMake添加版本信…

React 中使用 TS

目录 1&#xff0c;搭建项目2&#xff0c;tsconfig.json 相关配置项1&#xff0c; lib2&#xff0c;module3&#xff0c;jsx 3&#xff0c;在 React 中使用 TS3.1&#xff0c;TS 可以解决的问题3,2&#xff0c;函数式组件3.3&#xff0c;类组件3.4&#xff0c;Props 的默认值方…

#ESP32S3R8N8建立工程(VSCODE)点亮LED

1.参考文档 【立创ESP32S3R8N8】IDF入门手册 - 飞书云文档 (feishu.cn)https://lceda001.feishu.cn/wiki/GOIlwwfbIi1SC3k8594cDeFVn8g 2.建立工程 3.运行效果 4.更改配置 5.插播 之前配置的环境是有问题的&#xff0c;就算有自动检测也要仔细检查&#xff0c;必须严格按照以…

VMware安装ubuntun虚拟机使用桥接模式无法上网问题解决

问题&#xff1a;最近准备使用VMware虚拟机搭建k8s集群服务&#xff0c;因为需要在同一个网段下&#xff0c;我使用桥接的方式&#xff0c;我发现主机在使用有线连接时虚拟机网络连接正常&#xff0c;但是使用无线网就显示连接不上网络。 解决方法 一、查看网络连接&#xff…

aardio封装库) 微软开源的js引擎(ChakraCore)

前言 做爬虫肯定少不了JavaScript引擎的使用&#xff0c;比如在Python中现在一般用pyexecjs2来执行JavaScript代码&#xff0c;另外还有一些其他执行JavaScript的库&#xff1a; https://github.com/eight04/node_vm2: rpc调用nodejs&#xff0c;需要安装nodehttps://github.…

Spring Data JPA数据批量插入、批量更新真的用对了吗

Spring Data JPA系列 1、SpringBoot集成JPA及基本使用 2、Spring Data JPA Criteria查询、部分字段查询 3、Spring Data JPA数据批量插入、批量更新真的用对了吗 前言 在前两篇文章已经介绍过&#xff0c;在使用Spring Data JPA时&#xff0c;DAO层的Respository通过继承J…

BigKey的危害

1.2.1、BigKey的危害 网络阻塞 对BigKey执行读请求时&#xff0c;少量的QPS就可能导致带宽使用率被占满&#xff0c;导致Redis实例&#xff0c;乃至所在物理机变慢 数据倾斜 BigKey所在的Redis实例内存使用率远超其他实例&#xff0c;无法使数据分片的内存资源达到均衡 Redis阻…

Python中动画显示与gif生成

1. 动画生成 主要使用的是 matplotlib.animation &#xff0c;具体示例如下&#xff1a; import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np fig, ax plt.subplots() t np.linspace(0, 3, 40) g -9.81 v0 12 z g * t**2 / …

等保测评多选模拟题

21、以下哪些是黑客攻击手段&#xff1f;_____&#xff08;ABCDEFG&#xff09; A、暴力猜测 B、利用已知漏洞攻击 C、特洛伊木马 D、拒绝服务攻击 E、缓冲区溢出攻击 F、嗅探sniffer G、社会工程 22、计算机病毒的特点有_____。&#xff08; CD …

NFT是什么?有什么用途?

NFT&#xff0c;即非同质化代币&#xff08;Non-Fungible Token&#xff09;&#xff0c;是Web3技术的另一个重要应用。与比特币这样的同质化加密货币不同&#xff0c;NFT是独一无二的&#xff0c;每个代币都代表了一个独特的资产或物品。NFT通常基于区块链技术&#xff0c;如以…

新建stm32工程模板步骤

1.先使用keil新建一个project的基本代码 2.stm32启动文件添加 将stm32的启动文件&#xff0c;在原工程当中新建一个Start文件夹把相关的启动文件放到文件夹当中 然后还需要找到下面三个文件 stm32f10x.h是stm32的外设寄存器的声明和定义&#xff0c;后面那两个文件用于配置系…

深度学习 简记

深度学习个人学习简明笔记 待更新 文章目录 1 深度学习概论1.1 基本概念1.2 分类1.3 主要应用 2 神经网络基础2.1 神经网络组成2.2 前向传播与反向传播2.3 超参数2.4 激活函数2.5 优化方法2.5.1 基本梯度下降方法2.5.2 动量梯度下降2.5.3 Adam优化器 3 卷积神经网络(CNN)3.1 基…

【打工日常】Docker部署一款开源和自托管的平铺图像板系统

一、项目介绍1.项目简述Teedy是一个面向个人和企业的开源轻量级文档管理系统。2.项目功能保持组织:一个现代的界面,以保持您的重要文件在一个地方,您的业务操作清晰。上传&搜索:不要花费时间使用该工具,只需上传文档,然后在需要时轻松找到。安全:加密和数据中心将确…

【Docker】搭建一个媒体服务器插件后端API服务 - MetaTube

【Docker】搭建一个媒体服务器插件后端API服务 - MetaTube 前言 本教程基于群晖的NAS设备DS423的docker功能进行搭建&#xff0c;DSM版为 7.2.1-69057 Update 5。 简介 MetaTube 是一个媒体服务器插件&#xff0c;主要用于 Emby 和 Jellyfin 媒体服务器。它的主要功能是从互…

Java 笔记 11:Java 方法相关内容

一、前言 记录时间 [2024-05-01] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 02&#xff1a;Java 开发环境的搭建&#xff0c;IDEA / Notepad / JDK 安装及环境配置&#xff0c;编写第一个 Java 程序 Java 笔记 …

C++之const用法小结

在C中&#xff0c;const关键字具有多种用法&#xff0c;主要用于声明常量&#xff0c;确保某些变量的值在程序运行期间不会被修改。以下是const在C中的一些常见用法&#xff1a; 1.声明常量&#xff1a; 使用const声明的变量是常量&#xff0c;其值在初始化后不能再被修改。 …