【C++】总结2
文章目录
- 1.final和override关键字
- 2.extern "C"的用法
- 3.野指针和垂悬指针(悬空指针)
- 4.指针指向的内存被释放是什么意思
- 5.C和C++的类型安全
- 6.C++中的重载、重写(覆盖)和隐藏的区别
1.final和override关键字
final和override是C++11引入的关键字,用于在类的继承和虚函数重写中进行特定的语义声明
-
final
final关键字用于修饰类、成员函数或虚函数,表示它们是最终版本,不允许被继承、重写或覆盖
用于修饰类时,表示该类的最终类,不能被其他类继承
用于修饰成员函数时,表示该成员函数是最终版本,不能被子类的同名函数重写或覆盖。
class Base {public:virtual void foo() final; // 声明foo()是最终版本,不允许子类重写};class Derived : public Base {public:// 试图重写foo(),但由于在Base中声明为final,将会产生编译错误// void foo() override; // 错误,不能重写final函数};
-
override
override关键字用于修饰派生类中覆盖基类的虚函数,用于明确标识该函数是对基类虚函数的覆盖实现,提高代码的可读性和安全性
使用override关键字可以确保子类中的虚函数命名和基类中的虚函数一致,防止由于命名不一致而导致的意外。
class Base {public:virtual void foo();};class Derived : public Base {public:void foo() override; // 明确标识对基类虚函数foo()的覆盖};
总之:final关键字用于阻止类或成员函数的继承或重写,而override关键字用于明确标识派生类中对基类虚函数的覆盖实现。这两个关键字都提高了代码的安全性和可读性,并在面向对象编程中起到重要的作用。
2.extern "C"的用法
-
extern “C” 是C++中用于处理C语言和C++语言混合编程的关键字,在C++中,有时候需要与C语言的代码进行链接,或者在C++中调用C语言编写的函数,此时就可以使用extern “C” 来声明C语言的函数接口
-
当使用extern “C” 声明函数时,C++编译器会按照C语言的命名规则来处理该规则,这样可以确保C++和C的函数名在链接时保持一致,避免了由于C++的函数重载等特性导致的函数名修饰不一致的问题
-
假设有以下 C 语言的头文件
functions.h:
// functions.h#ifndef FUNCTIONS_H#define FUNCTIONS_Hint add(int a, int b);#endif // FUNCTIONS_H
- 对应的 C 语言源文件
functions.c实现了该头文件中的函数:
// functions.c#include "functions.h"int add(int a, int b) {return a + b;}
- 现在我们在 C++ 代码中想要调用
add函数,可以在 C++ 文件中这样声明:
// main.cpp#include <iostream>#include "functions.h"extern "C" {#include "functions.h" // 使用 extern "C" 包裹 include 指令}int main() {int result = add(5, 10);std::cout << "Result: " << result << std::endl;return 0;}
- 总结:
extern "C"用于在 C++ 中处理 C 语言的函数接口,保证函数名在链接时的一致性,从而实现 C 和 C++ 的混合编程。这在与 C 语言编写的库或代码进行交互时非常有用。
3.野指针和垂悬指针(悬空指针)
-
野指针是指指针指向的内存地址是无效的,即指针没有被正确初始化,或者指针指向的内存已经被释放,但指针本身还保留着原来的地址。
当我们使用野指针时,由于其指向的内存可能已经被其他程序或系统回收,所以访问该指针指向的内存会导致不可预测的行为,可能会导致程序崩溃或产生错误的结果
野指针的产生通常是由于以下原因:
- 1.未初始化指针:指针变量在定义后没有被正确初始化,它的值是随机的,可能指向任意内存地址
- 指针指向已释放的内存:在使用delete或free释放内存后,没有将指针置为nullptr
int* ptr = new int;delete ptr; // 释放内存后,ptr 成为野指针,应该将 ptr 置为 nullptrptr = nullptr;
- 指针误用:指针被错误的修改,导致它指向了无效的内存地址
int arr[5] = {1, 2, 3, 4, 5};int* ptr = &arr[0];ptr += 10; // ptr被错误地修改,指向了不属于arr的内存地址,ptr成为野指针
要避免使用野指针,我们要养成良好的编程习惯,确保指针在定义后都被正确初始化,并在释放指针指向的内存后,立即将指针置为nullptr。同时,不要随意修改指针的值,以防止野指针的产生
-
垂悬指针是指指针指向的内存已经被释放或释放后没有及时置空,导致指针的值仍然是之前指向的地址,但该地址的内容可能已经无效。当我们使用垂悬指针时,由于其指向的内存已经无效,访问该指针指向的内存会导致未定义行为,可能会产生不可预测的结果。
垂悬指针通常是由于以下原因产生:
- 释放后未置空:在使用
delete或free释放内存后,没有将指针置为nullptr
- 释放后未置空:在使用
int* ptr = new int;delete ptr; // 释放内存后,ptr 成为垂悬指针,应该将 ptr 置为 nullptrptr = nullptr;
-
- 引用悬挂:当指针指向一个引用,而该引用的生命周期已经结束,指针就会成为垂悬指针。
int a = 10;int& ref = a;int* ptr = &ref; // ptr 指向引用 ref,如果在之后 ref 的生命周期结束,ptr 就会成为垂悬指针
-
- 函数返回局部变量地址:在函数内部定义了一个局部变量,并返回其地址,但在函数结束后,该局部变量的内存已经被释放。
要避免使用垂悬指针,我们应该养成良好的编程习惯,在释放指针指向的内存后,立即将指针置为 nullptr。同时,在返回局部变量的指针时,应该确保返回的是有效的动态内存分配(堆内存)或者静态存储区(全局变量或静态变量)的地址。
4.指针指向的内存被释放是什么意思
释放内存意味着该内存不再属于当前程序,系统可以重新分配给其他程序使用。
5.C和C++的类型安全
-
类型安全是指编程语言或程序设计中的一种属性,确保在程序执行过程中不会发生不合法或未定义的类型操作,类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图访问自己没被授权的内存区域。类型安全保证了以下几点:
- 类型检查:在编译或运行时,编程语言会对类型进行检查,防止不同类型之间的非法操作
- 类型转换的明确性:在进行类型转换时,必须明确指定,避免隐式的不明确转换,从而降低类型错误的概率
- 类型兼容性:确保只有合法的类型转换才能进行,防止发生未定义行为或错误的结果
- 内存安全性:防止越界访问、空指针引用等导致的内存错误,从而提高程序的稳定性和安全性
-
C的类型安全性:
C是一种弱类型语言,类型的转换相对灵活,可以进行隐式类型转化,这使得C中存在潜在的类型错误和未定义行为;C编译器在类型检查方面较弱,无法在编译时完全捕获所有类型错误,可能会导致在运行时出现错误
以下是常见的例子
-
printf格式输出
int main() {printf("int类型输出:%d\n", 10);printf("float类型输出:%f\n", 10);return 0; }执行结果:
int类型输出:10 float类型输出:0.000000 -
malloc函数的返回值
malloc是C语言中用来进行内存分配的函数,它的返回类型是void* ,我们经常对结果进行类型转换, char* pstr=(char* )malloc(100*sizeof(char)),我们进行了显式类型转换,将void *类型转换为了char * 类型,sizeof的参数类型和显式转换的类型匹配的话,就没什么问题,但是如果不匹配,就很可能带来一些问题,如int * pstr=(int * )malloc(100 * sizeof(char)),而这样的转换C并不会提示错误。
-
-
C++的类型安全性
C++是一种静态类型语言,类型检查在编译时进行,所有类型的转换必须显式指定(除了一些隐式类型转换,如派生类向基类的指针转换)
C++ 提供了更强大的类型系统,包括强制类型转换(
static_cast、dynamic_cast、reinterpret_cast、const_cast)来明确指定类型转换,以及运算符重载来定义特定类型之间的操作。
6.C++中的重载、重写(覆盖)和隐藏的区别
-
重载
重载是指在同一个作用域内,函数名相同但参数列表不同的情况下,可以定义多个具有相同函数名但参数个数或类型不同的函数。
重载函数可以根据不同的参数来执行相似的操作,提高代码的复用性和可读性
重载函数在编译时通过参数个数、类型和顺序来决定调用哪个函数
class Math {public:int add(int a, int b);double add(double a, double b);};
-
重写/覆盖(override)
重写是指派生类重新定义基类中的虚函数
重写虚函数允许子类为基类的虚函数提供自己的实现,从而实现多态性
重写发生在类之间的继承关系中,子类函数与父类函数具有相同的函数名、参数列表和返回类型,并且基类函数必须声明为虚函数
class Shape {public:virtual void draw() {std::cout << "Drawing a shape." << std::endl;}};class Circle : public Shape {public:void draw() override {std::cout << "Drawing a circle." << std::endl;}};
-
重载和重写的区别:
- 重写是父类和子类之间的垂直关系,重载是不同函数之间的水平关系
- 重写要求参数列表相同,重载则要求参数列表不同,返回值不要求
- 重写关系中,调用方法根据对象类型决定,重载根据调用时实参与形参的对应关系来选择函数体
-
隐藏
隐藏是指在派生类中定义了一个与基类中同名但不具有虚函数特性的函数,这样它就会隐藏基类中的同名函数,包括以下情况:
- 两个函数参数相同,但是基类函数不是虚函数。如果基类函数是虚函数,则就是重写了。
//父类class A{public:void fun(int a){cout << "A中的fun函数" << endl;}};//子类class B : public A{public://隐藏父类的fun函数void fun(int a){cout << "B中的fun函数" << endl;}};int main(){B b;b.fun(2); //调用的是B中的fun函数b.A::fun(2); //调用A中fun函数return 0;}
- 两个函数参数不同,则无论基类函数是否是虚函数,都会被隐藏。和重载的区别在于两个函数不在同一个类中。
//父类class A {public:virtual void fun(int a) {cout << "A中的fun函数" << endl;}};//子类class B : public A {public://隐藏父类的fun函数virtual void fun(char* a) {cout << "A中的fun函数" << endl;}};int main() {B b;b.fun(2); //报错,调用的是B中的fun函数,参数类型不对b.A::fun(2); //调用A中fun函数return 0;}
- 基类指针指向派生类对象时,基类指针可以直接调用到派生类的覆盖函数,也可以通过 :: 调用基类被覆盖的虚函数;而基类指针只能调用基类的被隐藏函数,无法识别派生类中的隐藏函数。
相关文章:
【C++】总结2
文章目录 1.final和override关键字2.extern "C"的用法3.野指针和垂悬指针(悬空指针)4.指针指向的内存被释放是什么意思5.C和C的类型安全6.C中的重载、重写(覆盖)和隐藏的区别 1.final和override关键字 final和override是C11引入的关键字&…...
vue2项目中使用svg图标
在开发项目的时候经常会用到svg矢量图,而且我们使用SVG以后,页面上加载的不再是图片资源, 这对页面性能来说是个很大的提升,而且我们SVG文件比img要小的很多,放在项目中几乎不占用资源。 1、安装SVG依赖插件并配置加载器和路径 npm instal…...
阿里云盘自动每日签到无需部署无需服务器(仅限学习交流使用)
一、前言 阿里云盘自动每日签到,无需部署,无需服务器 执行思路:使用金山文档的每日定时任务,执行阿里云盘签到接口。 二、效果展示: 三、步骤: 1、进入金山文档网页版 金山文档官网:https:…...
Blazor前后端框架Known-V1.2.7
V1.2.7 Known是基于C#和Blazor开发的前后端分离快速开发框架,开箱即用,跨平台,一处代码,多处运行。 Gitee: https://gitee.com/known/KnownGithub:https://github.com/known/Known 概述 基于C#和Blazor…...
工业边缘计算为什么?
在工厂环境中使用边缘计算并不新鲜。可编程逻辑控制器(PLC)、微控制器、服务器和PC进行本地数据处理,甚至是微型数据中心都是边缘技术,已经在工厂系统中存在了几十年。在车间里看到的看板系统,打卡系统,历史…...
Training-Time-Friendly Network for Real-Time Object Detection 论文学习
1. 解决了什么问题? 目前的目标检测器很少能做到快速训练、快速推理,并同时保持准确率。直觉上,推理越快的检测器应该训练也很快,但大多数的实时检测器反而需要更长的训练时间。准确率高的检测器大致可分为两类:推理时…...
HTTP改HTTPS
tomcat中http协议改https 第一步,配置server.xml <?xml version"1.0" encoding"UTF-8"?> <Server port"8005" shutdown"SHUTDOWN"><Listener className"org.apache.catalina.startup.VersionLogger…...
网络层中一些零碎且易忘的知识点
异构网络:指传输介质、数据编码方式、链路控制协议以及数据单元格式和转发机制不同,异构即物理层和数据链路层均不同RIP、OSPF、BGP分别是哪一层的协议: -RIPOSPFBGP所属层次应用层网络层应用层封装在什么协议中UDPIPTCP 一个主机可以有多个I…...
【RabbitMQ】之高可用集群搭建
目录 一、RabbitMQ 集群原理 1、默认集群原理2、镜像集群原理3、负载均衡方案 二、RabbitMQ 高可用集群搭建 1、RabbitMQ 集群搭建2、配置镜像队列3、HAProxy 环境搭建4、Keepalived 环境搭建 一、RabbitMQ 集群简介 1、默认集群原理 3-1、RabbitMQ 集群简介 单台 RabbitM…...
【node.js】01-fs读写文件内容
目录 一、fs.readFile() 读取文件内容 二、fs.writeFile() 向指定的文件中写入内容 案例:整理txt 需求: 代码: 一、fs.readFile() 读取文件内容 代码: //导入fs模块,从来操作文件 const fs require(fs)// 2.调…...
GitHub仓库如何使用
核心:GitHub仓库如何使用 目录 1.创建仓库: 2.克隆仓库到本地: 3.添加、提交和推送更改: 4.分支管理: 5.拉取请求(Pull Requests): 6.合并代码: 7.其他功能&…...
雪花算法,在分布式环境下实现高效的ID生成
其实雪花算法比较简单,可能称不上什么算法就是一种构造UID的方法。 点1:UID是一个long类型的41位时间戳,10位存储机器码,12位存储序列号。 点2:时间戳的单位是毫秒,可以同时链接1024台机器,每台…...
使用css 动画实现,水波纹的效果
每日鸡汤:每个你想要学习的瞬间都是未来的你向自己求救 需求,实现水波纹动画效果,要求中心一个圆点,然后有3个圈,一圈一圈的向里面缩小。 说实话我第一个想到了给3个圈设置不同的宽高,然后设置动画0-100%&a…...
Unity光照相关知识和实践 (烘焙光照,环境光设置,全局光照)
简介 本文将会通过一个简单的场景搭建,介绍如何使用烘焙光照以及相关的注意事项。另外还介绍了Unity内全局光照(GI)的知识和GI实际在游戏内的表现效果。 Unity关于光照相关的参考文档地址:https://docs.unity.cn/cn/current/Man…...
【设计模式——学习笔记】23种设计模式——适配器模式Adapter(原理讲解+应用场景介绍+案例介绍+Java代码实现)
文章目录 介绍生活中的案例基础介绍工作原理分类应用场景 案例类适配器模式例1介绍类图代码实现优缺点分析 例2类图代码实现 对象适配器模式(常用方式)例1介绍类图代码实现优缺点分析 例2代码实现 接口适配器模式介绍类图代码实现 登场角色类图类适配器模…...
Android Unit Test
一、测试基础知识 1.1 测试级别 测试金字塔(如图 2 所示)说明了应用应如何包含三类测试(即小型、中型和大型测试): 小型测试是指单元测试,用于验证应用的行为,一次验证一个类。 中型测试是指…...
docker更新jenkins
下载文件 1、jenkins提示下载 2、官网下载jenkins官网 文件放服务器内 通过工具把jenkins.war放进服务器例如tmp 文件复制到docker的jenkins容器 docker cp 路径文件 容器id:/{后面不接内容为根路径} docker cp /tmp/jenkins.war 53dc1c71058a:/进入容器内 docker exec …...
一种新的基于区域的在线活动轮廓模型研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
【Docker】基于Dockerfile搭建LNMP架构
一、项目环境 公司在实际的生产环境中,需要使用Docker 技术在一台主机上创建LNMP服务并运行Wordpress网站平台。然后对此服务进行相关的性能调优和管理工作。 1. 环境配置 主机操作系统IP地址主要软件DockerCentOS 7.3 x86_64192.168.145.15Docker 19.03容器ip地址规划 ngin…...
爬虫003_pycharm的安装以及使用_以及python脚本模版设置---python工作笔记021
这里我们用ide,pycharm来编码,看一看如何下载 这里我们下载这个社区办,这个是免费的,个人版是收费的 然后勾选以后 安装以后我们来创建一个项目 这里可以选择python的解释器,选择右边的... 这里我们找到我们自己安装的python解释器...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
