C++类型转换方式总结

转换运算符的应用之所

const_cast、reinterpret_cast、static_cast、dynamic_cast转换运算符的使用总结如下:

  1. 对于传统的转换方式(C式或函数式),只在数值类型(包括整型、浮点型、字符类型和枚举)上使用。这也是延续C的形式,当然这类转换也是可以用static_cast来替换,但是因为是基本类型,所以传统转换已经很直观。
  2. 对于const_cast转换运算符,用在需要去除掉const限定的时候。其实这种情况出现的很少,可能的方法在const_cast一文中已经又举例,不过还是反复强调, 使用const_cast转换后,绝对不可试图修改结果的值。
  3. 对于reinterpret_cast转换运算符,一般用在将对象指针类型转换到整数类型或者void * (空指针)。如同在文中举出的隐患,因此注意的是,若要使用其结果,一定要将类型转换回去后使用。也不要将随意的整数转换成指针类型。
  4. 对于static_cast转换运算符,将其用在对象的转换之上(虽然static_cast也可以用在有继承关系的类型指针之间,但是还是将这方面的转换交给dynamic_cast来操作吧), static_cast会调用相应的构造函数或者重载的转换运算符。
  5. 通过Google C++ Style Guide的推荐格式,知道对于单参构造函数的存在可能会引发一些隐式的转换,因此用static_cast也可以明确的指出类型的转换过程,避免生成多余的临时对象造成效率下降。
  6. 对于dynamic_cast转换运算符,将其用在具有继承关系的指针类型之间的转换。无论是从基类到子类的转换,还是子类到基类的转换,都将dynamic_cast套上去。

如果任何一种基于指针或引用的转换,套上四个转换运算符之后都失败,那么所要进行的转换可能就触到了“雷区”了:进行了没意义的转换。比如,对于没有关系的两个类型的指针进行了转换,比如试图转换指向方法的指针了。所以转换运算符对于避免代码出错也很有帮助。

基于引用(Reference)的转换运算符使用

上述对于转换运算符的讲述和举例,都是基于指针的。但实际上,这些转换运算符也可以基于引用来展开。准确说实际上引用类型应该是作为转换的目标类型,源类型则是对象变量(当然也可能用的是引用变量,或是取出指针所指的内容,它们用到的都是实际的类对象)。

由于引用类型“定义时必须初始化”的特别,使得它不同于指针类型随时随地都调用转换运算符,基于引用的转换只在对引用进行初始化的时候才会出现。

下边是const_cast和reinterpret_cast基于引用的运用:

const int int_constant = 21;

int& int_ref = const_cast<int&>(int_constant);

cout << int_ref << endl;

int int_value = 7;

//long& long_ref = int_value; //Error, can not using reference cross types

float& long_ref = reinterpret_cast<float&> (int_value);

cout << long_ref << endl;

对于dynamic_cast的应用基本也是一致的,只是还是限制在具有继承关系的类型之间。不同于基于指针在转换时返回null,dynami_cast在基于引用转换失败时,会抛出std::bad_cast异常,因为不能将空值赋给引用类型。如果要抓住这个异常,则需要引入如下头文件:
#include <typeinfo>

而static_cast转换符前面已经说过推荐直接用在对象之上,不用在指针上,所以也不太会有需要用在引用类型上的情况出现。

山寨C#的TryParse

C#中有很多简洁实用的转换方法,比如从字符串到数值类型的Parse和TryParse,还有包含了各种从object对象到数值类型、时间类型的方法的Convert类,以及检查继承关系的as运算符。

从返回的结果看,C++和dynamic_cast和C#的as很相似,两者都是在失败时候返回null。

不过面向对象的关键点在于什么都是以对象为操作单位,如前所讲dynamic_cast看起来更像是一个全局方法。因此我便模仿C#的数值类的TryParse方法,写了一个包裹dynamic_cast的类型转换方法:

/

// dynamic_cast_tryparse.cpp

// Language:    C++

// Complier:    Visual Studio 2010, Xcode3.2.6

// Platform:    MacBook Pro 2010

// Application: none

// Author:      Ider, Syracuse University, ider.cs@gmail.com

///

#include <string>

#include <iostream>

using namespace std;

class Parents

{

public:

Parents(string n="Parent"){ name = n;}

virtual ~Parents(){}

virtual void Speak()

{

cout << "\tI am " << name << ", I love my children." << endl;

}

void Work()

{

cout << "\tI am " << name <<", I need to work for my family." << endl;;

}

/************** TryParseTo **************/

template<typename T> bool TryParseTo(T** outValue)

{

T* temp = dynamic_cast<T*> (this);

if (temp == NULL) return false;

*outValue = temp;

return true;

}

protected:

string name;

};

class Children : public Parents

{

public:

Children(string n="Child"):Parents(n){ }

virtual ~Children(){}

virtual void Speak()

{

cout << "\tI am " << name << ", I love my parents." << endl;

}

/*

**Children inherit Work() method from parents,

**it could be treated like part-time job.

*/

void Study()

{

cout << "\tI am " << name << ", I need to study for future." << endl;;

}

private:

//string name; //Inherit "name" member from Parents

};

class Stranger

{

public:

Stranger(string n="stranger"){name = n;}

virtual ~Stranger(){}

void Self_Introduce()

{

cout << "\tI am a stranger" << endl;

}

void Speak()

{

//cout << "I am a stranger" << endl;

cout << "\tDo not talk to "<< name << ", who is a stranger." << endl;

}

private:

string name;

};

int main()

{

Children * parsedChild;

Parents * parsedParent;

Stranger * parsedStranger;

Parents * mother = new Parents("Mother who pretend to be a my daugher");

if(mother->TryParseTo<Children>(&parsedChild))

parsedChild->Speak();

else

cout << "Parents parse to Children failed" << endl;

delete mother;

mother = new Children("Daughter who pretend to be a my mother");

if(mother->TryParseTo<Children>(&parsedChild))

parsedChild->Speak();

else

cout << "Parents parse to Children failed" << endl;

delete mother;

Children * son = new Children("Son who pretend to be a my father");

if(son->TryParseTo<Parents>(&parsedParent))

parsedParent->Speak();

else

cout << "Children parse to Parents failed" << endl;

if(son->TryParseTo<Stranger>(&parsedStranger))

parsedStranger->Speak();

else

cout << "Children parse to Stranger failed" << endl;

delete son;

//pointer of child class could pointer to base class object

/*

* son = new Parents("Father who pretend to be a my son");

if(son->TryParseTo<Parents>(&parsedParent))

parsedParent->Speak();

else

cout << "Parse failed" << endl;

delete son;

*/

return 0;

}

/********************* Result *********************/

//Parents parse to Children failed

//    I am Daughter who pretend to be a my mother, I love my parents.

//    I am Son who pretend to be a my father, I love my parents.

//Children parse to Stranger failed

这段代码中使用到的类跟dynamic_cast一文中使用的基本一样,只是在基类中多了一个模板方法:

template<typename T> bool TryParseTo(T** outValue)

{

T* temp = dynamic_cast<T*> (this);

if (temp == NULL) return false;

*outValue = temp;

return true;

}

该方法需要指定的目标类型,将自身指针转换成目标指针。转换成功,则将结果赋值给相应的变量,并返回真值;若失败则返回假值,不改变指针变量。因为要让外部的指针变量能够接受到改值,因此不得不使用指向指针的指针。

因为在基类中以公共结果的形式出现,所以每一个子类都继承了该方法,无论是基类的对象还是子类的对象都可以调用该方法。而该方法又不是虚方法,因此不并不希望子类去修改它。只是因为方法是模板方法,可能在编译的时候需要多花一些时间。

由于引用必须在定义时就赋值,并且dynamic_cast对于基于引用的转换不成功时将抛出异常,因此对于基于引用的转换,我还没有想出有什么好的山寨形式。

从测试代码的结果也可以看出,对于该发放的调用都是成功有效的。

所以又应了一句话:When use C++, the good news is that you can do everything you want, the bad news is that you have to do everything you want.

C++类型转换方式总结相关推荐

  1. C#调用C++的DLL 所有数据类型转换方式

    本以为这篇搜集整理的代码会是很不错的文章,花了一天时间,搜索到最后居然出来一篇叫做"C# 与 C++ 数据类型对照表"的文章.几乎囊括掉和大部分的数据了,太打击我了. 本文中有部分 ...

  2. 【C++】类型转换简述:四种类型转换方式的说明及应用

    本文主要简述在C++中四种类型转换的方式:static_cast.reniterpret_cast.const_cast和dynamic_cast. 在介绍C++类型转换方式之前,我们先来看看C语言的 ...

  3. python代码转换为pytorch_pytorch使用 to 进行类型转换方式

    在程序中,有多种方法进行强制类型转换. 本博文将介绍一个非常常用的方法:to()方法. 我们通常使用它来进行GPU和CPU的类型转换,但其实也可以用来进行torch的dtype转换. 常见方法:ten ...

  4. PG中的几种数据类型转换方式

    PG中的几种数据类型转换方式 1.通过格式化函数进行转换 函数 返回类型 描述 示例 to_char(timestamp,text) text 把时间戳转换成字符串 to_char(current_t ...

  5. 转:C#调用C++的DLL搜集整理的所有数据类型转换方式

    //C++中的DLL函数原型为         //extern "C" __declspec(dllexport) bool 方法名一(const char* 变量名1, uns ...

  6. 通读《C++ primer plus》— C++中的5种数据类型转换方式

    通读<C++ primer plus>-记录一 C++中的5种数据类型转换方式 1.始化和赋值时转换 比如 int a=1; long b=2147483647; a=b; 上面的代码并不 ...

  7. C++中四种类型转换方式(ynamic_cast,const_cast,static_cast,reinterpret_cast)

    Q:什么是C风格转换?什么是static_cast, dynamic_cast 以及 reinterpret_cast?区别是什么?为什么要注意? A:转换的含义是通过改变一个变量的类型为别的类型从而 ...

  8. C++中的4种类型转换方式

    类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比 ...

  9. C++中有哪些类型转换方式

    C++中四种类型转换运算符的使用方法 reinterpret_cast  该函数将 一个类型的指针 转换为 另一个类型的指针 .  这种转换不用修改指针变量值存放格式(不改变指针变量值),只需在编译时 ...

最新文章

  1. VMware linux虚拟机在线识别新添加磁盘
  2. js实现页面跳转重定向的几种方式
  3. Mysql中Drop删除用户的名字_mysql5.5 使用drop删除用户
  4. 项目以任务还是以功能为中心?
  5. 【华为云技术分享】Linux内核模块依赖图绘制(2)
  6. jsp,servlet交互驱动层实现
  7. C语言 100道经典编程题适用于专升本,专接本【详细分析版】
  8. Unity3d LED数码管单表控制/多表控制
  9. 五分钟就能上手的Android APP开发入门教程!!!
  10. 冰点下载:数据解析错误
  11. Matlab中滤波操作的相关函数
  12. B区考研学校排名计算机,b区(b区考研学校排名)
  13. 网络推广方式有哪些?分享几种常见的推广方式,十分有效
  14. 日本小学生走向APP开发私塾 智能手机迫切改变IT教育——日本经济新闻报道
  15. Unity获取麦克风实现吹气球效果
  16. 使用这5款模拟器访问备选操作系统
  17. 英格兰的政治+德意志的工业科技+犹太的金融+北美的丰富资源=世界NO.1强国
  18. Python3 math模块以及运算优先级
  19. electron应用通过web页面按钮唤醒
  20. XML基础(一)(只管能看懂XML文件)

热门文章

  1. Linux 命令(77)—— killall 命令
  2. ThinkPHP 数据库操作(一) : 连接数据库
  3. spring配置文件中id与name
  4. [DEncrypt] DESEncrypt--加密/解密帮助类 (转载)
  5. Sparrow - Distributed, Low Latency Scheduling
  6. Android 快捷方式
  7. 在线BMI身体质量指数计算器
  8. ACM题目中输入数据的处理(C++语言版)
  9. Java编程判断一组学生成绩等级
  10. 获取多个复选框的value