说实话,从来没有感觉到这个关键字有用,直到今天。

explicit的意思是明显的,和它相对应的一个词是implicit意思是隐藏的。

我参考了MSDN和《c++标准程序库》对这个关键字的描述,并参考了网络上对这个关键字的解释。现将它的使用方法和总结记录如下:

首先这个关键字只能用在类构造函数。它的作用是不能进行隐式转换。

class gxgExplicit  //没有关键字explicit的类

{

public:

int _size;

gxgExplicit(int size)

{

_size = size;

}

};

下面是调用

gxgExplicit gE1(24);     //这样是没有问题的

gxgExplicit gE2 = 1;     //这样也是没有问题的

gxgExplicit gE3;         //这样是不行的,没有默认构造函数

   gE1 = 2;                 //这样也是没有问题的

   gE2 = 3;                 //这样也是没有问题的

   gE2 = gE1;               //这样也是没有问题的

但是假如gxgExplicit修改为Stack,我们的_size代表的是堆栈的大小,那么调用的第二句就显得不伦不类,而且容易让人疑惑。这并不是可以让代码阅读者明白和接受的形式,虽然它是合法的(编译器可以通过编译)。这是因为编译器默认情况下有隐式转换的功能,你输入gE2 = 1就编译成同第一句相同的结果。所以,explicit就派上了用场。修改代码为:

class gxgExplicit

{

public:

int _size;

explicit gxgExplicit(int size)

{

_size = size;

}

};

继续上面的调用:

gxgExplicit gE1(24);     //这样是没有问题的

gxgExplicit gE2 = 1;     //这样是不行的,关键字取消了隐式转换

gxgExplicit gE3;         //这样是不行的,没有默认构造函数

   gE1 = 2;                 //这样是不行的,关键字取消了隐式转换

   gE2 = 3;                 //这样是不行的,关键字取消了隐式转换

   gE2 = gE1;               //这样是不行的,关键字取消了隐式转换,除非类实现操作符“=”的重载。

这是编译器(vs2005)显示:cannot convert from 'int' to 'gxgExplicit'

从这里也就看出这个关键字的作用是将编译器隐式转换的功能给屏蔽掉

MSDN上有一个注意点描述了下面的事实,当构造函数参数超过两个时自动取消隐式转换。例如

class gxgExplicit

{

private:

int _size;

int _age;

public:

explicit gxgExplicit(int age, int size)

{

_age = age;

_size = size;

}

};

这是有没有关键字效果是一样的。那就是相当于有这个关键字。

但是另外一种情况例外:其中只有一个必须输入的参数,其余的为有默认值的参数。

class gxgExplicit

{

private:

int _size;

int _age;

public:

explicit gxgExplicit(int age, int size = 0)

{

_age = age;

_size = size;

}

};

class gxgExplicit

{

private:

int _size;

int _age;

int _hight;

public:

explicit gxgExplicit(int age, int size = 0)

{

_age = age;

_size = size;

_hight = hight;

}

};

这样的情况下相当于一个参数的效果。

到现在为止。这个关键字就是这么用了。

呵呵,今天来好好看看着几个转换操作符的用法。以前老是看着眼熟,但是用着手生。今天决定搞定这些个东西。

在C语言中类型转换有几种方式:

1.      (expression). 在表达式外边加括号,由编译器来决定怎么改变。

2.      new_type(expression). 强制类型括号住表达式。

3.      (new_type)expression. 括号住强制类型。

4.      C语言允许的内置转换。

这些转换非常高效,我非常喜欢使用。特别是在指针转换和数值转换时用到的非常多。只要编写程序的人知道自己要做什么转换,并知道应该怎样转换的话,我认为上边的转换方式非常之好。但是没有清楚的了解每个转换的细节的话,就有可能出现问题,比如指针指向不应该指向的区域:出现野指针或者指向位置错误(主要是对内存结构不了解),或者计算数值被截去等问题发生。

C++程序兼容C语言的转化,但是针对面向对象语言的特性,设计了以下几个类型转换操作符。他们的出现是为了C语言类型转换中语义模糊和固有的危险陷阱,因为C语言不去判断所要操作的类型转换是否合理。

static_cast:用于非多态类型的转换。

dynamic_cast:用于多态类型的转换。

const_cast:用来消除const, volatile, __unaligned属性的转换。

reinterpret_cast:用于空间的重新解释。

还有一个在VS2005中出现的类型转换关键字safe_cast.#2

static_cast:

static_cast<type_id>(expression)

这个关键字可以用来将一个指针转换为父类的指针也可以转换为子类的指针或者基本的类型转换。但是这种转换是强制的,并没有任何运行时类型检查来保证转换的正确性,所以编写代码的人需要明白自己所进行的转换是否合理。

//基本类型的转换

enum e { A = 1, B, C };

double d = 12.25;

unsigned int ui = 25;

char c = static_cast<char>(ui);

int i = static_cast<int>(d);

int j = static_cast<int>(B);

//父类子类转换

class F                  //father

{

public:

int _father;

};

class S : public F       //son

{

public:

_son;

};

F *pFather = new F();

S *pSon = new S();

F *pF;

S *pS;

pF = static_cast<F *>(pSon);    //将子类指针转换为父类指针,OK

pS = static_cast<S *>(pFather); //将父类指针转换为子类指针,错误

第二个错误的转换不是说编译器编译不过去,而是运行时会出现错误。

原因如下:假设pF指向了pSon的位置,它可以访问_father,它找不到_son,这样没有问题。但是pS指向了pFather的位置,它访问_father没有问题,但是访问_son时就会产生错误,因为pFather根本没有_son这个变量。

下面是将父类转换为子类指针时,static_cast和dymanic_cast两者不同的表现:

class F

{

public:

virtual void speak(){};

int i;

};

class S : public F

{

public:

void speak()

{

cout << "S = " << _s << endl;

}

double _s;

};

F *pF = new F();

S *pS = static_cast<S*>(pF);

pS->speak();

S1 *pDS = dynamic_cast<S*>(pF);

pDS->speak();

静态的转换编译不显示警告,运行结果不输出(调用F的speak函数)。动态的转换编译显示可能出现不可预期的结果,运行时崩溃。(VS2005时,返回空指针,但是不会崩溃。我认为要是按照C++的特性还是崩溃比较好一点,让程序员容易理解这么做是错误的。)

dynamic_cast:

dynamic_cast<type_id>(expression)

本关键字主要处理多态的类型转换,type_id要么是指针类型,要么是引用类型要么是void*。当type_id为指针和void*时,expression必须是type_id类型的指针,当type_id为引用时,expression也必须是type_id类型的引用。#1

1.最常用的用法就是将子类指针转换为父类指针。(不举例)

2.当type_id为void*时,指针指向整个对象的空间。

Class A;

A *pA = new A();

void *p = dynamic_cast<void*>(pA);

但是type_id不为void*时,计算机就要在运行时检查是否能够转换。

3.跳级转换。

class A{};

class B : public A{};

class C : public B{};

A *pA;

B *pB;

C *pC = new C();

pB = dynamic_cast<B*>(pD);  //逐级转换OK

pA = dynamic_cast<A*>(pB);  //逐级转换OK

或者

pA = dynamic_cast<A*>(pC);  //跳级转换OK

delete pD;

以下情况跳级转换不可以:

class A{};

class B : public A{};

class C : public A{};

class D : public B, public C{};

A *pA;

D *pD = new D();

pA = dynamic_cast<A*>(pB);  //出现错误,是不行的,原因大家都清楚。

class A{};

class B : public A{};

class C : public A{};

class D : public B{};

class E : public C, public D{};

A *pA;

B *pB;

E *pE = new E();

pB = dynamic_cast<B*>(pE);

pA = dynamic_cast<A*>(pB);  //可以

pA = dynamic_cast<A*>(pE);  //不可以,原因是很简单的。

delete pE;

4.两个不相干的类之间转换。

class A {};

class B {};

A* pa = new A;

B* pb = dynamic_cast<B*>(pa);   // 不可以,没有相互转换的基础

但是reinterpret_cast可以转换,可以参考reinterpret_cast

const_cast:

const_cast<type_id>(expression)

这个关键字消除了几个关键字的作用const, volatile,和__unaligned的作用。const经常使用。MSDN有const的例子照抄过来。

class CCTest {

public:

void setNumber( int );

void printNumber() const;

private:

int number;

};

void CCTest::setNumber( int num ) { number = num; }

void CCTest::printNumber() const {

cout << "\nBefore: " << number;

const_cast< CCTest * >( this )->number--;//这里消除了const的作用

cout << "\nAfter: " << number;

}

int main() {

CCTest X;

X.setNumber( 8 );

X.printNumber();

}

reinterpret_cast:

reinterpret_cast

这个关键字比较“强悍”,随意转换类型。但是转换错误,就是你的不对了。呵呵,我的原则两个字:“慎用”。

这个关键字可以在任何类型的指针之间转换。

不可以替代const_cast。

不提供安全转换。

MSDN的例子显示出来它的强悍,也显示出了他的脆弱。只要你一个不小心就会乱用。

#include <iostream>

// Returns a hash code based on an address

unsigned short Hash( void *p ) {

unsigned int val = reinterpret_cast<unsigned int>( p );

return ( unsigned short )( val ^ (val >> 16));

}

using namespace std;

int main() {

int a[20];

for ( int i = 0; i < 20; i++ )

cout << Hash( a + i ) << endl;

}

#1 dynamic_cast的type_id为引用的情况我不准备了解,好像是微软VS2005的特性,而不是标准C++的特性。对于VS6.0我还是感觉比较欣赏的。虽然不如他的新版本那样支持更多的C++特性,但是我自己的感觉是VS的产品在无限的向C#靠拢,无限的向java的易用性靠拢,这样的话C++程序在抑制到别的操作系统时就需要做很大的修改。这也是微软的霸道之处。题外话:微软的vista是一款失败的产品,在vista上微软开发了virtual PC 2007的虚拟机,但是这款产品只支持windows系统的产品安装,对于linux产品他就不支持(只能安装,不能用),因为他不支持24位真彩色。这就说明它的心态是封闭的,而封闭最终导致它的衰败。

#2 safe_cast也是微软的东西,想了解的请参考VS2005的MSDN。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/callmeback/archive/2009/04/01/4040583.aspx

转载于:https://my.oschina.net/alphajay/blog/28723

Explicit 关键字和各种类型转换(转)相关推荐

  1. 【C++】explicit关键字

    explicit的优点是可以避免不合时宜的类型变换,缺点无.所以google约定所有单参数的构造函数都必须是显式的** explicit关键字只需用于类内的单参数构造函数前面.由于无参数的构造函数和多 ...

  2. C++中的explicit关键字介绍

    C++中的关键字explicit主要是用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换.类构造函数默认情况下声明为隐式的即implicit. 隐式转 ...

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

    C++中explicit关键字的作用 explicit用来防止由构造函数定义的隐式转换. 要明白它的作用,首先要了解隐式转换:可以用单个实参来调用的构造函数定义了从形参类型到该类类型的一个隐式转换. ...

  4. C++explicit关键字

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105089138 C ...

  5. 【c++】【转】c++中的explicit关键字

    http://www.cnblogs.com/chio/archive/2007/09/17/895263.html c++中的explicit关键字用来修饰类的构造函数,表明该构造函数是显式(调用) ...

  6. C++11 explicit关键字的作用

    explicit 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换.因为无参构造函数和多参构造函数本身就是显示调用 ...

  7. 深入理解C++中的explicit关键字

    深入理解C++中的explicit关键字 kezunhai@gmail.com http://blog.csdn.net/kezunhai C++中的explicit关键字只能用于修饰只有一个参数的构 ...

  8. C++中的explicit关键字用法

    c++中的explicit关键字用来修饰类的构造函数,被修饰的类的构造函数不能进行隐式类型的转换,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐 ...

  9. C++ explicit关键字

    我们先看下面的代码 class A {public://构造函数A(int a = 0):_a(a){}//拷贝构造A(const A& a){_a = a._a;}private:int _ ...

  10. 【转】认识 C++ 中的 explicit 关键字

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

最新文章

  1. 决策树算法(二)——构建数据集
  2. 从ffmpeg源代码分析如何解决ffmpeg编码的延迟问题(如何解决编码 0 延时)
  3. 关于Jsp页面的jstl标签的级联属性的异常。
  4. P2495-[SDOI2011]消耗战【虚树,dp】
  5. 前端学习(476):web前端行业介绍
  6. Redis java客户端操作
  7. AI 崛起,科学家的天下,程序员的谢幕
  8. lua 和 c交互详解(一)
  9. 线程、协程、Goroutine的区别和联系
  10. 论文笔记_S2D.72_RGB图像和不确定性引导的稀疏噪声激光雷达深度补全
  11. Matlab论文插图绘制模板第19期—散点折线图
  12. echarts 生成 迁徙图_echarts迁徙图
  13. dxp全称_Protel DXP 2004 分立元件库元件名称中英对照表
  14. 中华石杉-- --消息队列的笔记
  15. java中后台的跳转_java后台跳转
  16. 计算机组成原理——总线(课程笔记)
  17. Java培训学习之分词工具之HanLP介绍
  18. 领导让谈入职公司的感受
  19. nginx proxy_pass规则
  20. 红外线 电磁波频谱

热门文章

  1. linux ac 命令
  2. Android Studio的单元测试
  3. 通过telegram 传递变量_Docker随时随地玩转变量
  4. 入门React第二天(函数式组件传值)
  5. Echarts横向的柱状图
  6. 程序包androidx.appcompat.app不存在
  7. so运行出错:只包含了头文件,未同时编译cpp
  8. 苹果机查看macOS版本号
  9. LINUX虚拟机安装增强功能
  10. 项目关键路径与项目最长路径有可能不同