当前位置: 首页 > news >正文

C++总结(3):类的动态内存分配、异常、类型转换运算符

文章目录

  • 1 类的动态内存分配
    • 1.1 C++动态内存分配
    • 1.2 拷贝构造函数
    • 1.3 赋值运算符(operator=)重载
  • 2 异常
  • 3 类型转换运算符

1 类的动态内存分配

1.1 C++动态内存分配

在C/C++中都可以使用malloc/free来分配内存,但C++还有一种更好的方法:newdelete。下面以动态分配int类型的变量为例,来看看如何使用这两个关键字:

(1)变量

int *pn = new int;
delete pn;

(2)数组

int *psome = new int[10];
delete []psome;

1.2 拷贝构造函数

拷贝构造函数是用于将一个对象复制到新创建的对象中,如果用户没有声明拷贝构造函数的话,编译器将生成一个默认的拷贝构造函数,它将逐个赋值非静态成员。它的原型如下:

Class_name(const Class_name &)

假设有一个String类,motto是一个String类对象,它的拷贝构造函数为String(const String &),它的拷贝构造函数被调用的时机有以下几种:

String ditto(motto);
String metto = motto;
String also = String(motto);
String *pString = new String(motto)

所以如果有一个函数传的参数是String类形参,而不是引用的话,编译器将临时使用拷贝构造函数创建一个该类的副本。假设String类的构造函数中有分配内存,析构函数中有释放内存。此时若用户没有定义自己的拷贝构造函数,则编译器会调用默认的拷贝构造函数(而不是构造函数),而在这个函数调用完后,将调用析构函数释放内存。这就会导致一些内存错误。应该自己定义一个拷贝构造函数,如下所示:

String(const String& other)
{  len = other.len;  str = new char[len + 1];  strcpy(str, other.str);
}  
  • 一个函数如果返回对象的引用则不会调用拷贝构造函数,否则将调用拷贝构造函数。

1.3 赋值运算符(operator=)重载

前面我们知道String metto = motto;将调用拷贝构造函数,那什么时候调用拷贝构造函数,什么时候调用赋值运算符重载:在类定义的时候的=调用拷贝构造函数,在类定义完后的=调用赋值运算符重载:

调用拷贝构造函数:
String metto = motto;
调用赋值运算符重载:
String metto;
metto = motto;

与复制构造函数相似,赋值运算符的隐式实现也对成员进行逐个复制。所以对于上面的metto = motto来说,如果metto原本就通过动态内存分配分配了一块内存,这样隐式的拷贝就会导致之前的内存来不及释放。应该自己定义一个赋值运算符重载函数,如下所示:

String & String::operator=(const String & st)
{if (this == &st)return *this;delete [] str;len = st.len;str = new char [len + 1];strcpy(str, st .str) ;return *this;
}

2 异常

C++异常是对程序运行过程中发生的异常情况的一种响应。异常提供了将控制权从程序的一个部分传递到另外一部分的途径。C++可以使用try-catch来捕获异常,直接来看一个求调和平均值2ab/(a+b)的例子:

double hmean(double a, double b);int main(){double x, y, z;std::cout << "Enter two numbers: ";while (std::cin >> x >> y){try{z = hmean(x,y);}catch(const char * s){  // start of exception handlerstd::cout << s << std::endl;std::cout << "Enter a new pair of numbers: ";continue;}                       // end of handlerstd::cout << "Harmonic mean of " << x << " and " << y<< " is " << z << std::endl;}return 0;
}double hmean(double a, double b){if(a==-b){throw "bad hmean() arguments: a = -b not allowed";}return 2.0 * a * b / (a+b);
}

try块中的代码若判断出异常后,throw一个异常(类似跳转,同时退出当前函数),就能被catch捕获。下面再来看一下将对象用作异常类型的例子:

#include<iostream>class bad_hmean{
private:double v1;double v2;
public:bad_hmean(int a = 0, int b = 0) : v1(a), v2(b) {}void mesg();
};inline void bad_hmean::mesg(){std::cout << "hmean(" << v1 << ", " << v2 << "): "<< "invalid arguments: a = -b\n";
}
double hmean(double a, double b);int main(){using std::cout;using std::cin;using std::endl;double x, y, z;cout << "Enter two numbers: ";while(cin >> x >> y){try { // start of try blockz = hmean(x, y);cout << "Harmonic mean of " << x << " and " << y<< " is " << z << endl;}catch(bad_hmean & bh){ // start of catch blockbh.mesg();cout << "Try again.\n";continue;}}return 0;
}double hmean(double a, double b){if (a==-b){throw bad_hmean(a,b);//算作局部变量,等catch结束后该变量将销毁}return 2.0 * a * b / (a + b);
}

也就是说发送异常时可以throw一个类,然后在catch时使用bad_hmean & bh获得这个对象的引用。

3 类型转换运算符

C语言中的强制类型转换允许几乎所有情况的转换,比如将一个指针的地址转换为char,这样就输出的是这个32位指针变量的地址的低8位(大端)。显然,这种转换是没有意义的,大概率是程序员写错了,所以C++有几种更严格的类型转换机制:

(1)dynamic_cast

用于在运行时执行安全的向下类型转换,通常用于处理多态类型的类层次结构,如继承关系。

dynamic_cast<type_name>(expression)type_name:目标类型的名称,通常是一个类或类的指针/引用类型。expression:是要进行类型转换的表达式,通常是指向基类对象的指针或引用。

dynamic_cast 会检查是否可以安全地将 expression 转换为 type_name 类型,如果可以,它将返回一个指向目标类型的指针(或引用),否则返回一个空指针(如果转换失败)或抛出 std::bad_cast 异常(如果转换不安全)。下面看一个例子:

#include<iostream>using namespace std;class Shape {
public:virtual void draw() { cout<<"shape"<<endl; }
};class Circle : public Shape {
public:void draw() override { cout<<"circle"<<endl; }void specialCircleFunction() { cout<<"special circle"<<endl; }
};int main() {Shape* shape = new Circle;Circle* circle = dynamic_cast<Circle*>(shape);if (circle) {circle->specialCircleFunction();} else {// 转换失败}delete shape;return 0;
}

(2)const_cast

用于添加或去除对象的 const 限定符,以便在需要时更改对象的常量性。通常情况下,const_cast 用于修改指向 const 对象的指针或引用,以使其可以修改对象的值。但要注意,滥用 const_cast 可能会导致未定义的行为,因此应该谨慎使用。

const_cast<new_type>(expression)new_type:要转换成的类型。expression:要进行类型转换的表达式,通常是指向const对象的指针或引用。

下面看一个例子:

#include <iostream>int main() {const int x = 10;const int* ptr1 = &x;int* ptr2 = const_cast<int*>(ptr1); // 使用const_cast去除const限定符*ptr2 = 30;std::cout << "After modification: x = " << x << std::endl;return 0;
}

(3)static_cast

用于执行编译时类型转换,可以在合理的情况下将一个类型转换为另一个相关类型,例如将整数转换为浮点数。但要注意,static_cast 不提供运行时检查,因此必须确保类型转换是安全的。

static_cast<new_type>(expression)new_type:要转换成的目标类型。expression:要进行类型转换的表达式。

下面来看一个例子:

#include <iostream>int main() {int integerNumber = 42;double doubleNumber = static_cast<double>(integerNumber);std::cout << "Double Number: " << doubleNumber << std::endl;return 0;
}

需要注意的是,static_cast 不执行运行时检查,因此在使用时需要谨慎,确保类型转换是安全的。如果转换不安全,可以考虑使用 dynamic_cast 或其他类型转换运算符进行更安全的类型转换。

(4)reinterpret_cast

用于执行低层的类型转换,允许你将一个指针类型转换为另一种不相关的指针类型,或者将任何类型转换为一个完全不同的类型。这是最不安全的类型转换之一,因为它不会进行任何类型检查或转换操作。

reinterpret_cast<new_type>(expression)new_type:要转换成的目标类型。expression:要进行类型转换的表达式,通常是指针、引用或其他表达式。

下面看一个例子,这里用static_cast的话就无法编译通过。

#include <iostream>int main()
{int array[5] = {1, 2, 3, 4, 5};int* ptr = array;char* charPtr = reinterpret_cast<char*>(ptr);std::cout << "First element of array (as char): " << static_cast<int>(charPtr[0]) << std::endl;return 0;
}

这是一个非常危险的操作,因为它忽略了数据的实际类型和结构。所以reinterpret_cast 应该非常小心地使用,只有在确切清楚这种类型转换是必要的情况下才应使用。

相关文章:

C++总结(3):类的动态内存分配、异常、类型转换运算符

文章目录 1 类的动态内存分配1.1 C动态内存分配1.2 拷贝构造函数1.3 赋值运算符(operator)重载 2 异常3 类型转换运算符 1 类的动态内存分配 1.1 C动态内存分配 在C/C中都可以使用malloc/free来分配内存&#xff0c;但C还有一种更好的方法&#xff1a;new和delete。下面以动态…...

折半搜索(meet in the middle)

介绍 折半搜索&#xff0c;又称 meet in the middle \text{meet in the middle} meet in the middle&#xff0c;指将整个搜索过程分为两部分&#xff0c;并对两部分分别进行搜索&#xff0c;最后得到两个答案序列&#xff0c;将这两个答案序列进行合并&#xff0c;即可得到最…...

【机器学习】loss损失讨论

大纲 验证集loss上升&#xff0c;准确率也上升&#xff08;即将overfitting&#xff1f;&#xff09;训练集loss一定为要为0吗 Q1. 验证集loss上升&#xff0c;准确率也上升 随着置信度的增加&#xff0c;一小部分点的预测结果是错误的&#xff08;log lik 给出了指数级的惩…...

LeetCode 779. 第K个语法符号【递归,找规律,位运算】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

java try throw exception finally 遇上 return break continue造成异常丢失

如下所示&#xff0c;是一个java笔试题&#xff0c;考察的是抛出异常之后&#xff0c;程序运行结果&#xff0c;但是这里抛出异常&#xff0c;并没有捕获异常&#xff0c;而是通过finally来进行了流程控制处理。 package com.xxx.test;public class ExceptionFlow {public sta…...

设计模式——装饰器模式(Decorator Pattern)+ Spring相关源码

文章目录 一、装饰器模式的定义二、个人理解举个抽象的例&#xff08;可能并不是很贴切&#xff09; 三、例子1、菜鸟教程例子1.1、定义对象1.2、定义装饰器 3、JDK源码 ——包装类4、JDK源码 —— IO、OutputStreamWriter5、Spring源码 —— BeanWrapperImpl5、SpringMVC源码 …...

MATLAB R2018b详细安装教程(附资源)

云盘链接&#xff1a; pan.baidu.com/s/1SsfNtlG96umfXdhaEOPT1g 提取码&#xff1a;1024 大小&#xff1a;11.77GB 安装环境&#xff1a;Win10/Win8/Win7 安装步骤&#xff1a; 1.鼠标右击【R2018b(64bit)】压缩包选择【解压到 R2018b(64bit)】 2.打开解压后的文件夹中的…...

GEE错误——影像加载过程中出现的图层无法展示的解决方案

问题&#xff1a; // I dont know if some standard value exists for the radius, in the same, I will assume that some software would prefer to use square shape, but circle makes more sense to me. // pixels is noice if you want to zoom in and out to visualize…...

读图数据库实战笔记03_遍历

1. Gremlin Server只将数据存储在内存中 1.1. 如果停止Gremlin Server&#xff0c;将丢失数据库里的所有数据 2. 概念 2.1. 遍历&#xff08;动词&#xff09; 2.1.1. 当在图数据库中导航时&#xff0c;从顶点到边或从边到顶点的移动过程 2.1.2. 类似于在关系数据库中的查…...

QT如何检测当前系统是是Windows还是Uninx或Mac?以及是哪个版本?

简介 通过Qt获取当前系统及版本号&#xff0c;需要用到QSysInfo。 QSysInfo类提供有关系统的信息。 WordSize指定了应用程序编译所在的平台的指针大小。 ByteOrder指定了平台是大端序还是小端序。 某些常量仅在特定的平台上定义。您可以使用预处理器符号Q_OS_WIN和Q_OS_MACOS来…...

Maven配置阿里云中央仓库settings.xml

Maven配置阿里云settings.xml 前言一、阿里云settings.xml二、使用步骤1.任意目录创建settings.xml2.使用阿里云仓库 总结 前言 国内网络从maven中央仓库下载文件通常是比较慢的&#xff0c;所以建议配置阿里云代理镜像以提高jar包下载速度&#xff0c;IDEA中我们需要配置自己…...

由浅入深C系列八:如何高效使用和处理Json格式的数据

如何高效使用和处理JSON格式的数据 问题引入关于CJSON示例代码头文件引用处理数据 问题引入 最近的项目在用c处理后台的数据时&#xff0c;因为好多外部接口都在使用Json格式作为返回的数据结构和数据描述&#xff0c;如何在c中高效使用和处理Json格式的数据就成为了必须要解决…...

多媒体应用设计师 第16章 多媒体应用系统的设计和实现示例

口诀 思维导图 2020...

golang平滑重启库overseer实现原理

overseer主要完成了三部分功能&#xff1a; 1、连接的无损关闭&#xff0c;2、连接的平滑重启&#xff0c;3、文件变更的自动重启。 下面依次讲一下&#xff1a; 一、连接的无损关闭 golang官方的net包是不支持连接的无损关闭的&#xff0c;当主监听协程退出时&#xff0c;…...

用Python定义一个函数,用递归的方式模拟汉诺塔问题

【任务需求】 定义一个函数&#xff0c;用递归的方式模拟汉诺塔问题&#xff0c;三个柱子&#xff0c;分别为A、B、C&#xff0c;其中A柱子上有N个盘子&#xff0c;从小到大编号为1到N&#xff0c;盘子大小不同。现在要将这N个盘子从A柱子移动到C柱子上&#xff0c;但移动的过…...

二手的需求

案例1030 某天项目经理小王&#xff0c;从用户现场带回了需求&#xff0c;以图形的方式&#xff0c;交给了产品经理。告诉他就照这样设计&#xff0c;结果是项目经理放弃让产品经理出效果图。 原因是产品经理觉得项目经理带回来的需求有问题。项目经理解释产品经理不接受&…...

大厂面试题-JVM为什么使用元空间替换了永久代?

目录 面试解析 问题答案 面试解析 我们都知道Java8以及以后的版本中&#xff0c;JVM运行时数据区的结构都在慢慢调整和优化。但实际上这些变化&#xff0c;对于业务开发的小伙伴来说&#xff0c;没有任何影响。 因此我可以说&#xff0c;99%的人都回答不出这个问题。 但是…...

基本微信小程序的驾校宝典系统-驾照考试系统

项目介绍 系统模块分析是对系统的各个模块做出相应的说明以及解释。此系统的模块分别有用户模块、服务端模块和管理端模块这两大基本模块&#xff0c;其中服务端模块包括了首页、教练信息、教练咨讯、考试预约、我的等&#xff1b;而管理端模块则包括了个人中心、用户管理、教…...

02、SpringCloud -- Redis和Cookie过期时间刷新功能

目录 需求:代码流程过滤器类工具类过滤判断远程调用feign接口gitee 配置接口实现过滤器run方法测试:问题:秒杀功能完整分析图 需求: cookie应该写在网关中,网关中可以自定义filter过滤器,用来实现cookie的刷新和redis中key的刷新,延长用户的操作时间。 就是让用户每操…...

【报错】kali安装ngrok报错解决办法(zsh: exec format error: ./ngrok)

问题描述 kali安装ngrok令牌授权失败 在安装配置文件的时候报错&#xff1a;zsh: exec format error: ./ngrok 原因分析&#xff1a; 在Kali Linux上执行./ngrok时出现zsh exec格式错误的问题可能是由于未安装正确版本的ngrok或操作系统不兼容ngrok导致的。以下是一些可能的解…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...