一 隐式类型转换概念:
隐式类型转换指的是编译器在不需要显式指定转换的情况下,将一种类型的值转换为另一种类型
隐式类型转变不仅可以对内置类型使用而且可以对自定义类型使用,那接下来我们分别讨论。
二 内置类型与自定义类型隐式转换:
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)
,并初始化其成员变量 _x
为 42
。
总结:
没有优化时:先调用构造函数创建一个临时对象 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;
}