C++隐式转换与explicit关键字

本文深入探讨了C++中的隐式转换概念,包括其定义、发生条件及风险,特别是自定义类的构造函数如何引发隐式转换。文章还介绍了explicit关键字如何用于控制这些转换,避免潜在的程序逻辑错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

隐式转换定义

Implicit conversions are performed whenever an expression of some type T1 is used in context that does not accept that type, but accepts some other type T2; in particular:

  • when the expression is used as the argument when calling a function that is declared with T2 as parameter;
  • when the expression is used as an operand with an operator that expects T2;
  • when initializing a new object of type T2, including return statement in a function returning T2;
  • when the expression is used in a switch statement (T2 is integral type);
  • when the expression is used in an if statement or a loop (T2 is bool).

所谓隐式转换,是指不需要用户干预,编译器私下进行的类型转换行为。很多时候用户可能都不知道进行了哪些转换。

隐式转换的发生条件

这里只讨论自定义的类的隐式转换发生条件。对于基本数据类型,隐式转换发生在取值范围从小->大,低精度->高精度的转换中。
按照默认规定,只要有一个构造函数,C++就会为这个构造函数定义一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象。
例子:

class String{
public:
    int n;
    char * p;
    String(int n){ this->n = n; }
    String (int a, int b, int c){
        this->n = a+b+c;
    }
};

String s1 = 10; //可以:隐式转换调用String(int n);再调用默认的复制构造函数
String s10 = {1,2,3}; 	//可以:隐式转换调用String(int a, int b, int c);
						//再调用默认的复制构造函数

隐式转换的风险

隐式转换的风险也一般存在于自定义的类构造函数中。

例子1:

class String
{
public:
    String ( int n ); //本意是预先分配n个字节给字符串
    String ( const char* p ); // 用C风格的字符串p作为初始化值
 
    //…
}

下面两种写法比较正常:

String s2 ( 10 );   //OK 分配10个字节的空字符串
String s3 = String ( 10 ); //OK 分配10个字节的空字符串

下面两种写法就比较疑惑了:

String s4 = 10; //编译通过,也是分配10个字节的空字符串
String s5 = ‘a’; //编译通过,分配int(‘a’)个字节的空字符串

s4 和s5 分别把一个int型和char型,隐式转换成了分配若干字节的空字符串,容易令人误解。

explicit的作用

==通过将构造函数声明为explicit(显式)的方式可以抑制隐式转换。==也就是说,explicit构造函数必须显式调用。

class String{
public:
    int n;
    char * p;
    explicit String(int n){ this->n = n; }
    String ( const char* p ); 
    explicit String(int a, int b, int c){
        this->n = a+b+c;
    }
};

String s1 = 10; ///错误:不能做隐式int->String转换
String s2(10);  //可以:调用explicit String(int n);
String s3 = String(10);//可以:调用explicit String(int n);再调用默认的复制构造函数
String s4('a'); //可以:char->int 调用explicit String(int n);
				//再调用默认的复制构造函数
String s5 = {1,2,3}; //错误:不能调用隐式转换String(int a, int b, int c);
String s6(1,2,3); //可以:调用String(int a, int b, int c);
					//再调用默认的复制构造函数
String s7 = "Brian"; //可以:隐式转换调用String(const char *p);
					 //再调用默认的复制构造函数

隐式转换常常带来程序逻辑的错误,而且这种错误一旦发生是很难察觉的。
原则上应该在所有的构造函数前加explicit关键字,当你有心利用隐式转换的时候再去解除explicit,这样可以大大减少错误的发生。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值