在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。

explicit使用注意事项:

*     explicit 关键字只能用于类内部的构造函数声明上。

*     explicit 关键字作用于单个参数的构造函数。

*     在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换。

在C++中,如果一个类有只有一个参数的构造函数,C++允许一种特殊的声明类变量的方式。在这种情况下,可以直接将一个对应于构造函数参数类型的数据直接赋值给类变量,
编译器在编译时会自动进行类型转换,将对应于构造函数参数类型的数据转换为类的对象。如果在构造函数前加上explicit修饰词,则会禁止这种自动转换,在这种情况下,即使将
对应于构造函数参数类型的数据直接赋值给类变量,编译器也会报错。
下面以具体实例来说明。
  建立people.cpp 文件,然后输入下列内容: 
class People 

public: 
int age; People (int a)  {    age=a;  } 
};

void foo ( void ) 
{   
People p1(10);  //方式一  
People* p_p2=new People(10); //方式二  
People p3=10; //方式三 
}

这段C++程序定义了一个类people,包含一个构造函数,这个构造函数只包含一个整形参数a,可用于在构造类时初始化age变量。
然后定义了一个函数foo,在这个函数中我们用三种方式分别创建了三个10岁的“人”。
第一种是最一般的类变量声明方式。
第二种方式其实是声明了一个people类的指针变量,然后在堆中动态创建了一个people实例,并把这个实例的地址赋值给了p_p2.
第三种方式就是我们所说的特殊方式,为什么说特殊呢?我们都知道,C/C++是一种强类型语言,不同的数据类型是不能随意转换的,
如果要进行类型转换,必须进行显式强制类型转换,而这里,没有进行任何显式的转换,直接将一个整型数据赋值给了类变量p3.

因此,可以说,这里进行了一次隐式类型转换,编译器自动将对应于构造函数参数类型的数据转换为了该类的对象,
因此方式三经编译器自动转换后和方式一最终的实现方式是一样的。

explicit关键字到底是什么作用呢?它的作用就是禁止这个特性。如文章一开始而言,凡是用explicit关键字修饰的构造函数,
编译时就不会进行自动转换,而会报错。

以下再以几个例子来加深印象:
 
例子一: 未加explicit时的隐式类型转换 
class Circle  
{  
public:  
Circle(double r) : R(r) {} 
Circle(int x, int y = 0) : X(x), Y(y) {}  
Circle(const Circle& c) : R(c.R), X(c.X), Y(c.Y) {}

private:  
double R;  
int X;  
int Y;  
};  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
//发生隐式类型转换  
//编译器会将它变成如下代码  
//tmp = Circle(1.23)  
//Circle A(tmp);  
//tmp.~Circle();  
Circle A = 1.23;  
//注意是int型的,调用的是Circle(int x, int y = 0)  
//它虽然有2个参数,但后一个有默认值,仍然能发生隐式转换
Circle B = 123;  
//这个算隐式调用了拷贝构造函数  
Circle C = A; 
return 0;  
}

加了explicit关键字后,可防止以上隐式类型转换发生 
class Circle  
{  
public:  
explicit Circle(double r) : R(r) {}  
explicit Circle(int x, int y = 0) : X(x), Y(y) {}  
explicit Circle(const Circle& c) : R(c.R), X(c.X), Y(c.Y) {}  
private:  
double R;  
int X;  
int Y;  
};  
 
int _tmain(int argc, _TCHAR* argv[])  
{  
//一下3句,都会报错  
//Circle A = 1.23;  
//Circle B = 123;  
//Circle C = A;

//只能用显示的方式调用了  
//未给拷贝构造函数加explicit之前可以这样  
Circle A = Circle(1.23);  
Circle B = Circle(123);  
Circle C = A;

//给拷贝构造函数加了explicit后只能这样了  
Circle A(1.23);  
Circle B(123);

Circle C(A);

return 0;  
}

例子二:
class   A   
{    
public:                
A(int); 
private:    
int   num;      
};  
  
int   Test(const   A&)   //   一个应用函数 
{
...      

   
Test(2);   //   正确    
过程是这样的:   编译器知道传的值是int而函数需要的是A类型,但它也同时知道调用A的构造函数将int转换成一个合适的A,
所以才有上面成功的调用.换句话说,编译器处理这个调用时的情形类似下面这样:    
const  A  temp(2);   //   从2产生一个临时A对象 
Test(temp);          //   调用函数       
 
如果代码写成如下样子:  
class  A    
{   
public:    
explicit   A(int); 
private:    
int   num;    
};

int   Test(const   A&)   //   一个应用函数     
{    
        ...    
}

Test(2);   //   失败,不能通过隐式类型转换将int类型变量构造成成A类型变量.

例子三:
按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示: 
class String 

String ( const char* p ); // 用C风格的字符串p作为初始化值      
//…
}

String s1 = “hello”; //OK 隐式转换,等价于String s1 = String(“hello”);  
 
但是有的时候可能会不需要这种隐式转换,
如下: class String
 { 
        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 关键字: 
class String
{        
explicit String ( int n ); //本意是预先分配n个字节给字符串
        String ( const char* p ); // 用C风格的字符串p作为初始化值        
//… 
}

加上explicit,就抑制了String ( int n )的隐式转换,
下面两种写法仍然正确: 
String s2 ( 10 );   //OK 分配10个字节的空字符串
String s3 = String ( 10 ); //OK 分配10个字节的空字符串

下面两种写法就不允许了:  
String s4 = 10; //编译不通过,不允许隐式的转换 
String s5 = ‘a’; //编译不通过,不允许隐式的转换  
因此,某些时候,explicit 可以有效得防止构造函数的隐式转换带来的错误或者误解。
====================================================================================================
explicit只对构造函数起作用,用来抑制隐式转换。如:     
class   A
{               
A(int   a);     
};  
     
int   Function(A   a);      
当调用Function(2)的时候,2会隐式转换为A类型。这种情况常常不是程序员想要的结果,所以,要避免之,就可以这样写:     
class   A
{               
explicit   A(int   a);      
}; 
      
int   Function(A   a);          
这样,当调用Function(2)的时候,编译器会给出错误信息(除非Function有个以int为参数的重载形式),这就避免了在程序员毫不知情的情况下出现错误。
 注意:只是用于一个参数的构造函数,如:
1、constructor(typename value); 
2、construcor(typename value1,typename value2=defaultvalue,typename value3=defaultvalue,...) ),
因为两个参数的构造函数几乎没办法隐式的转换,即无法出现classtype classname = value;的情况(因为这样只能赋给一个值)。

C++explicit关键字的更多相关文章

  1. C++ explicit关键字详解

    本文系转载,原文链接:http://www.cnblogs.com/ymy124/p/3632634.html 首先, C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用 ...

  2. C++中explicit关键字的使用

    看书看到了explicit关键字,就来做个笔记,讲得比较明白,比较浅. 在C++中,我们有时可以将构造函数用作自动类型转换函数.但这种自动特性并非总是合乎要求的,有时会导致意外的类型转换,因此,C++ ...

  3. C++中的explicit关键字

    http://www.cnblogs.com/winnersun/archive/2011/07/16/2108440.html 上面链接中的博主写的很好,我也不多说了.举得例子也很好,应该也是看了E ...

  4. C++中explicit关键字的作用

    转载自:http://www.cnblogs.com/winnersun/archive/2011/07/16/2108440.html explicit用来防止由构造函数定义的隐式转换. 要明白它的 ...

  5. C++ explicit关键字应用方法详解

    C++编程语言中有很多比较重要的关键字在实际编程中起着非常重要的作用.我们今天为大家介绍的C++ explicit关键字就是其中一个应用比较频繁的关键字.下面就让我们一起来看看这方面的知识吧. C++ ...

  6. explicit关键字

    C++中,explicit关键字用来修饰类只有一个参数的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换. explicit使用注意事项: explicit 关 ...

  7. C++ 构造函数放置默认转换explicit关键字(2)

    按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示: class String { String ( const char* p );  ...

  8. explicit 关键字

    C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢? 如果c++类 ...

  9. 从零开始学C++之构造函数与析构函数(一):构造函数、析构函数、赋值与初始化、explicit关键字

    一.构造函数.默认构造函数 (1).构造函数 构造函数是特殊的成员函数 创建类类型的新对象,系统自动会调用构造函数 构造函数是为了保证对象的每个数据成员都被正确初始化 函数名和类名完全相同 不能定义构 ...

随机推荐

  1. 【Android Studio】No JVM installation found

    如果没有配置好JDK的环境变量,启动Android Studio的时候会报错: 请参考我整理的博客文章<JDK的下载.安装和配置>,链接:http://www.cnblogs.com/du ...

  2. bzoj1227 [SDOI2009]虔诚的墓主人(组合公式+离散化+线段树)

    1227: [SDOI2009]虔诚的墓主人 Time Limit: 5 Sec  Memory Limit: 259 MBSubmit: 803  Solved: 372[Submit][Statu ...

  3. HAProxy、Nginx 配置 HTTP/2 完整指南

    基于最近对HTTP/2的争论和它的优势,是时候升级底层架构了.这篇文章将会介绍如何在安装和配置HAProxy和Ngnix(使用ssl终端).为了简化流程,我建议你准备好使用Docker镜像. 如果你想 ...

  4. Chapter 1. OpenGL基础回顾 - Review of OpenGL Basics

    译自<OpenGL® Shading Language, Second Edition> 本章主要回顾OpenGL应用编程接口,为后续章节中的材质铺垫基础.这并不是详尽的回顾.如果你已经 ...

  5. Core OS 层

    Core OS层的底层功能是很多其他技术的构建基础.通常情况下,这些功能不会直接应用于应用程序,而是应用于其他框架.但是,在直接处理安全事务或和某个外设通讯的时候,则必须要应用到该层的框架. Acce ...

  6. [PWA] 17. Cache the photo

    To cache photo, You need to spreate cache db to save the photo. So in wittr example, we cache the te ...

  7. 解决Xcode6.0.1编译Unity3Dproject报错

    错误信息大概例如以下 Undefined symbols for architecture i386: "_clock$UNIX2003",.....等 大概就是引用了一个链接库出 ...

  8. window7 远程连接 拒绝访问

    windows7 远程连接 拒绝访问 ----------------------------- 找了很多网络文章,都没有解决问题. 然后突然: 用Administrator超级管理员修改了一下 想要 ...

  9. Day3 - Python基础3 函数、递归、内置函数

    Python之路,Day3 - Python基础3   本节内容 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8. ...

  10. oracle中的function 、procedure、packages、package bodies比较

    1  function和procedure的区别 1).可以理解函数是存储过程的一种 2).函数可以没有参数,但是一定需要一个返回值,存储过程可以没有参数,不需要返回值 3).函数return返回值没 ...