1 :C++中的隐式转换和explicit关键字
1.1 隐式转换
C++中的隐式转换是指在某些情况下,编译器会自动将一种数据类型转换为另一种数据类型,而无需显式地使用类型转换运算符。
以下是一些常见的隐式转换情况:
整数类型之间的转换。例如,将一个short类型的变量赋值给一个int类型的变量,或者将一个char类型的变量与一个int类型的变量进行运算。
浮点类型之间的转换。例如,将一个float类型的变量赋值给一个double类型的变量。
数组类型和指针类型之间的转换。例如,将一个数组名作为参数传递给函数时,它会自动转换为一个指向数组第一个元素的指针。
派生类和基类之间的转换。例如,将一个派生类的对象赋值给一个基类的引用或指针时,编译器会自动进行向上转型。
需要注意的是,虽然隐式转换可以方便我们的编程,但有时也可能会带来一些意想不到的问题。因此,在编写代码时应该尽量避免过多地依赖隐式转换,以确保程序的正确性和可读性。
在64位电脑上,常见的数据类型的字节数、比特数和表示范围如下所示:
整数类型:
- int:4字节(32位),32比特,范围为-2,147,483,648到2,147,483,647。
- short:2字节(16位),16比特,范围为-32,768到32,767。
- long:8字节(64位),64比特,范围为-9,223,372,036,854,775,808到9,223,372,036,854,775,807。
- long long:8字节(64位),64比特,范围为-9,223,372,036,854,775,808到9,223,372,036,854,775,807。
浮点类型:
- float:4字节(32位),32比特,范围为约±1.18E-38到±3.4E+38,精度约为6位小数。
- double:8字节(64位),64比特,范围为约±2.23E-308到±1.8E+308,精度约为15位小数。
- long double:8字节(64位),64比特,范围和精度与double相同,但可能提供更高的精度。
字符类型:
- char:1字节(8位),8比特,通常用于表示ASCII字符,范围为-128到127或0到255(取决于是否有符号)。
常见的数据类型:
隐式转换:
数字类型之间的隐式转换:
- 较小的整数类型可以隐式转换为较大的整数类型,例如将short转换为int,int转换为long。
- 整数类型可以隐式转换为浮点类型,例如将int转换为float,long转换为double。
- **浮点类型可以隐式转换为更高精度的浮点类型,**例如将float转换为double。
字符类型之间的隐式转换:
- 字符类型可以隐式转换为整数类型,例如将char转换为int。
枚举类型之间的隐式转换:
- **不同枚举类型之间的值可以相互隐式转换,**但建议使用显式转换以避免潜在的错误。
指针类型之间的隐式转换:
- 具有继承关系的类指针之间可以进行隐式转换,例如将派生类指针转换为基类指针。
- void指针可以隐式转换为任意类型的指针,但需要注意在转换后正确处理类型。
需要注意的是,隐式转换可能会导致精度损失或数据截断,因此在进行隐式转换时应谨慎,并确保不会引发意外的错误
1.2 隐式构造函数
在C++中,隐式构造函数(Implicit Constructor)指的是可以通过单个参数调用的构造函数,用于将该参数类型转换为类的对象。隐式构造函数允许在某些情况下,通过隐式地进行类型转换来创建对象。
1 :单参数构造函数:如果一个类具有只接受单个参数的构造函数,那么在需要该类对象的地方,可以使用该参数类型进行隐式构造。
构造函数初始化列表知识补充:
ClassName::ClassName(parameters) : member1(value1), member2(value2), ... {
// 构造函数的其他代码
}
其中: ClassName 是类的名称。 parameters 是构造函数的参数列表。 member1(value1), member2(value2), ... 是初始化列表,用于对类的成员变量进行初始化。每个成员变量都以逗号分隔,格式为成员变量名(初始值)。 在初始化列表中,可以使用传递给构造函数的参数或其他常量、表达式等来初始化成员变量。
以下是一个示例
class MyClass {
public:
MyClass(int value1, int value2) : m_member1(value1), m_member2(value2) {
// 构造函数的其他
[Something went wrong, please try again later.]
关于隐式构造函数:
#include <iostream>
using namespace std;
class MyInt{
public:
MyInt(int value):m_value(value){}//初始化列表
int getValue() const {return m_value;} //return 里面一定记得带封号
private:
int m_value;
};
void printMyInt(MyInt myint){
cout << "MyInt value" << myint.getValue() << endl;
}
int main(){
printMyInt(10); // 隐式构造MyInt对象
return 0;
}
代码解析:
1:定义了一个名为MyInt的类,具有一个接受单个int类型参数的构造函数和一个返回成员变量值的成员函数getValue()。
2:定义了一个名为printMyInt的函数,接受一个MyInt对象作为参数,并打印出该对象的值。 3:在main()函数中,通过调用printMyInt()函数并传递整数值10作为参数,隐式地构造了一个 MyInt对象,并将其传递给printMyInt()函数进行打印。
4:程序最后返回0,表示正常退出。
int getValue() const {return m_value;}
注意:该函数返回一个整数类型的值,表示存储在MyInt对象中的整数值。由于该函数不会修改任何成员变量的值,因此使用了const关键字来修饰函数,以保证该函数不会对对象的状态进行修改。其中,const关键字位于函数声明的末尾,表示该函数是一个常量成员函数。在函数体内,我们直接返回成员变量m_value的值,以便从外部访问该值。
结果:
1.3 explicit 关键字
在C++中,explicit是一个关键字,用于修饰单参数构造函数。当构造函数被声明为explicit时,它将禁止隐式的类型转换。 通常情况下,如果一个类的构造函数只有一个参数,那么可以使用该构造函数进行隐式的类型转换。但是,如果将构造函数声明为explicit,则编译器将不会自动执行隐式的类型转换,而要求显式地调用构造函数。
#include <iostream>
class MyInt{
public:
explicit MyInt(int value):m_value(value){
//构造函数其他代码
}
int getValue()const{
return m_value;
}
private:
int m_value;
};
void printValue(const MyInt& myint){
int value = myint.getValue();
std::cout << "Value:" << value << std::endl;
}
int main(){
MyInt myint1(10);//直接调用构造函数进行初始化
printValue(myint1);//调用printValue函数,隐式转换成MyInt类型
//MyInt myint2 = 20;//错误,禁止使用隐式转换
//printValue(30);//禁止使用隐式转换
return 0;
}
printValue(20): 是使用隐式构造函数;
printValue(myint1); 是隐式将myint1 隐式转换成MyInt类型。