C++ 类和对象 隐式类型转换

ops/2024/11/9 17:08:25/

一 隐式类型转换概念:

隐式类型转换指的是编译器在不需要显式指定转换的情况下,将一种类型的值转换为另一种类型

隐式类型转变不仅可以对内置类型使用而且可以对自定义类型使用,那接下来我们分别讨论。

二 内置类型与自定义类型隐式转换:

2.1 内置类型隐式转换:

int main()
{double b = 4.56;int a = b;printf("%d", a);return 0;
}

在该代码转换过程中,编译器会创建一个临时的常量变量 const double temp = b; 来保存 b 的值。这是为了确保原变量 b 不会在转换过程中被修改。

临时变量 temp 的值(即 4.56)会被转换为 int 类型。在这个转换过程中,小数部分被截断,只保留整数部分。因此,temp 的值 4.56 转换为 int 类型后变成 4

转换后的整数值 4 被赋值给变量 a

这就是内置类型中的隐式转换,接来让我们看看自定义类型是怎么转换的

2.2 自定义类型隐式转换:

#include <iostream>class C {
public:C(int x) : _x(x) {std::cout << "C(int) constructor called with x = " << x << std::endl;}C(const C& other) {_x = other._x;std::cout << "Copy constructor called" << std::endl;}private:int _x;
};int main() 
{int value = 42;C a(10);C obj = value;  // 隐式类型转换return 0;
}

在主函数中有两个初始化,第一个是我们比较常用的也是最熟悉的直接初始化,那第二个为什么可以直接将内置类型赋值给对象cc2呢,好像这样也没有给_x赋值,那下面咱们就来讲讲为什么可以初始化成功。

2.2.1 复制初始化:

复制初始化是一种使用 = 操作符进行对象初始化的方式。与直接初始化不同,复制初始化涉及类型转换和潜在的复制构造操作。其过程如下:

优化前:首先C obj = value;这段代码是将整数传给自定义类型因它们一个是自定义类型一个是内置类型所以我们会创建一个临时对象Temp然后编译器会在C类中看有没有一个接受 int 类型参数的构造函数,如果有就执行它找到的构造函数,(如果没有的话那编译器将会报错,提示没有可用的构造函数来进行这种类型转换) 然后再传递参数,此时临时对象 temp_x 成员变量被初始化为 42

那现在只是临时对象的成员变量被初始化了,而目标对象还没有,这时就要调用拷贝构造函数将临时对象的成员变量 _x 赋值给目标对象的成员变量 _x。

优化后:

编译器会优化掉临时对象的创建,直接在目标对象 obj 的内存位置上调用构造函数 C(int x),并初始化其成员变量 _x42

总结:

没有优化时:先调用构造函数创建一个临时对象 temp,初始化其成员变量 _x,然后使用拷贝构造函数将临时对象的成员变量 _x 赋值给目标对象的成员变量 _x

有优化时:直接在目标对象 obj 的位置上调用构造函数进行初始化,不需要创建临时对象,也不需要使用拷贝构造函数。

上面搞懂之后咱们来看看如果目标对象是const修饰或者不是const修饰的情况:

class C
{
public:C(int x): _x(x){std::cout << "C(" << x << ") constructed\n";}~C(){std::cout << "C(" << _x << ") destructed\n";}private:int _x;
};int main()
{C& cc4 = C(3);//错误C obj(4);C& cc5 = obj;return 0;
}

输出:

为什么上面那个错误,而下面就是正确的呢?

原因在于字面量如 3 不是一个完整的对象,而是一个值,不能直接绑定到非 const 引用上,在C++中,引用必须绑定到一个已经存在的对象上。引用本质上是对象的别名,它不能像指针那样独立存在,所以下面的他先是将对象成员初始化然后再让它赋值给目标对象

三 explicit关键字:

当一个类的构造函数只接受一个参数时,该构造函数可以被隐式调用。这意味着编译器可能会在需要该类对象的地方自动创建一个临时对象,从而进行隐式类型转换。

这种隐式类型转换有时会导致意外的行为或错误。为了解决这个问题,可以在构造函数前添加 explicit 关键字,禁止编译器进行隐式类型转换。

代码示例:

class C
{
public:/* explicit */C(int x): _x(x){}private:int _x;
};int main()
{C obj(1);C a = 1;return 0;
}

四 多个参数隐式类型:

在C++中,当你定义一个构造函数时,可以通过提供多个参数来支持隐式类型转换。

代码示例:

class Point 
{
public:Point(double x, double y) : _x(x), _y(y) {}private:double _x;double _y;
};int main()
{Point b(1, 2);//构造函数Point a = { 1, 2 };//多个参数隐式传值return 0;
}


http://www.ppmy.cn/ops/87594.html

相关文章

【C++】模拟实现string类

模拟实现string类 模拟实现string类浅拷贝与深拷贝写时拷贝&#xff08;了解&#xff09;string类的模拟实现代码 链接: 认识使用string类 前文已经讲解过如何使用string类&#xff0c;下面主要讲解如何模拟实现常用的string类函数&#xff0c;以及对深拷贝和浅拷贝的讲解。 …

【爱上C++】vector用法详解

文章目录 一:vector简介二:vector的创建和初始化三:vector的遍历1.[]下标2.at()3.迭代器遍历4.范围for 四:vector的空间1.size2.max_size3.capacity4.reserve5.resize6.empty 五:vector的增删查改1.push_back2.pop_back3.find4.insert5.erase6.swap7.assign Hello~同学们好&…

【c语言】你绝对没见过的预处理技巧

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C语言 目录 前言 一、预定义符号 二、#define定义常量 三、#define定义宏 四、宏与函数的对比 五、#操作符和##操作符 1.#操作符 2.##操作符 六、#unde…

⭐️2024年7月全球排名前二十开发语言全面对比横向竖向PK(TIOBE指数榜单)编程语言介绍 适用场景 优势 举例 详细说明 编写第一个语言程序Hello world源代码

2024年7月全球排名前二十开发语言全面对比横向竖向PK&#xff08;TIOBE指数榜单&#xff09;编程语言介绍 适用场景 优势 举例 详细说明 编写第一个语言程序Hello world源代码 2024年7月全球排名前二十开发语言全面对比横向竖向PK&#xff08;TIOBE指数榜单&#xff09;编程语言…

PyQt5| 界面设计 |利用Qt Designer实现简单界面交互

目录 1 QtDesigner简单界面设计2 代码部分2.1 ui文件转py文件2.2 界面文件代码2.3 主文件代码2.3.1 主体框架代码2.3.2 实现交互代码 3结果展示 准备工作&#xff1a; 配置好PyQt5相关的库、QtDesigner、pyuic 1 QtDesigner简单界面设计 点击“工具"——>“外部工具&a…

【教程】从零开始用QT简易实现modbus通信

前言&#xff1a;本文旨在让读者了解在qt6中实现modbus通信主要使用哪些函数&#xff0c;需要引用哪些库和头文件&#xff0c;不对modbus协议进行介绍&#xff0c;仅在代码层面简单实现一个modbus通信案例 实现效果&#xff1a;点击读取按钮可以读取从机中的十个寄存器&#x…

string类的介绍与使用【C++】

string类 前言一、为什么学习string类C语言中的字符串示例 二、标准库中的string类string类string类的常用接口说明string类对象的常见构造string类对象的容量操作string的接口测试及使用string类对象的访问及遍历操作下标和方括号遍历范围for遍历迭代器遍历相同的代码&#xf…

vscode-python的debug 教学(最全)

vscode中的python-debugger的使用 Visual Studio Code 的主要功能之一是其强大的调试支持。VS Code 的内置调试器有助于加速编辑、编译和调试循环。 一、 安装python-debugger插件 在插件库内搜索python Debugger&#xff0c;安装插件 三、 进行debug&#xff08;不带参数…