C++类型转换


隐式类型转换:

C++的隐式转换发生在以下四种情况:

  • 在混合类型的算术表达式中。
  • 在表达式赋值中。
  • 表达式传给函数时,实参转换为形参的类型。
  • 函数返回表达式时转换成返回值类型。

显式类型转换:

  • 被称为“强制类型转换”(cast)
  • C风格:(type-id)
  • C++风格:static_castdynamic_castreinterpret_cast、和const_cast

1. static_cast

  • 用法:static_cast < type-id > ( expression )
  • 通常用于转换数值类型,进行非多态的类型转换。
  • 在转换时不进行类型检查,在编译时进行类型检查,如果转换不成功则编译错误,因此不安全。
// static_cast_Operator.cpp
// compile with: /LD
class B {};

class D : public B {};

void f(B* pb, D* pd) {
   D* pd2 = static_cast<D*>(pb);   // Down
                                   // Not safe, D can have fields
                                   // and methods that are not in B.

   B* pb2 = static_cast<B*>(pd);   // Up
                                   // Safe conversion, D always contains all of B.
}
  • 与 dynamic_cast 不同,pb 的 static_cast 转换不执行运行时检查。 由 pb 指向的对象可能不是 D 类型的对象,在这种情况下使用 *pd2 会是灾难性的。 例如,调用 D 类(而非 B 类)的成员函数可能会导致访问冲突。

2. dynamic_cast

  • 用法:dynamic_cast < type-id > ( expression )
  • 用于指针和引用。不同类型的指针和引用之间的转换。
  • 注意dynamic_cast在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上。也即如果想将基类指针转换为派生类指针,如果基类不是虚类则无法实现
  • 被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。
  • 向上转换和static_cast作用一样。不要求虚基类。
  • 支持同一个基类的不同派生类指针之间的转换。而static_cast则会报错。
  • 失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时)。例子如下。
// static_cast_Operator_2.cpp
// compile with: /LD /GR
class B {
public:
   virtual void Test(){}
};
class D : public B {};

void f(B* pb) {
   D* pd1 = dynamic_cast<D*>(pb);
   D* pd2 = static_cast<D*>(pb);
}
  • 如果 pb 确实指向 D 类型的对象,则 pd1pd2 将获取相同的值。 如果 pb == 0,它们也将获取相同的值。
  • 如果 pb 指向 B 类型的对象,而非指向完整的 D 类,则 dynamic_cast 足以判断返回零。 但是,static_cast 依赖于程序员的断言,即 pb 指向 D 类型的对象,因而只是返回指向那个假定的 D 对象的指针。

3. reinpreter_cast

  • 用法:reinpreter_cast<type-id> (expression)
  • type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
  • 它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。
  • 比较底层的转换,在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。reinpreter_cast是特意用于底层的强制转型,导致实现依赖(就是说,不可移植)的结果。

4. const_cast

  • 用法:const_cast<type_id> (expression)
  • 该运算符用来修改类型的constvolatile属性。除了constvolatile修饰之外, type_idexpression的类型是一样的。
  • 常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

关于多态的类指针转换

  • 向上转换:派生类指针转为基类指针。
  • 向下转换:基类指针转换为派生类指针。

见下面这个例子:

class A {
 public:
   A() {
     a = 0;
   }
 private:
   int a;
};

class B : public A {
 public:
   B() {
     b = 0;
   }
 private:
   int b;
};
int main() {
  A *pa1, *pa2, *pa3, *pa4;
  B *pb1, *pb2, *pb3;

  A a1;
  pa1 = &a1;
  B b1;
  pb1 = &b1;
  
  // 首先,对于指针直接指向对象:
  pa2 = &b1;  // Correct 指针pa直接指向B中A有的一部分
  pb2 = &a1;  // Error 需要进行强制类型转换来缩小pb指针的范围
              // error: invalid conversion from 'A*' to 'B*'

  // 指针之间的转换
  pa3 = dynamic_cast<A*>(pb3);  // Up Correct 见上,使得指针能够正常工作
  pb3 = dynamic_cast<B*>(pa4);  // Down Error
  // error: cannot dynamic_cast 'pa4' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
  // 由于类A不是虚基类,不能将其指针pa转换为类B的指针,因为类B的指针能够对A中没有的内容进行操作,直接转换则不能做到。若A为虚基类,B是对A中方法的重写,则能够正确转换

  return 0;
}

例子:

  • 此转换类型称为“向上转换”,因为它将在类层次结构上的指针,从派生的类移到该类派生的类。 向上转换是一种隐式转换。
class B { };
class C : public B { };
class D : public C { };

void f(D* pd) {
   C* pc = dynamic_cast<C*>(pd);   // ok: C is a direct base class
                                   // pc points to C subobject of pd 
   B* pb = dynamic_cast<B*>(pd);   // ok: B is an indirect base class
                                   // pb points to B subobject of pd
}
  • 此转换类型称为“向下转换”,因为它将在类层次结构下的指针,从给定的类移到该类派生的类。
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
   B* pb = new D;   // unclear but ok
   B* pb2 = new B;

   D* pd = dynamic_cast<D*>(pb);   // ok: pb actually points to a D
   D* pd2 = dynamic_cast<D*>(pb2);   // pb2 points to a B not a D
}

参考阅读

static_cast, dynamic_cast, const_cast探讨
static_cast 运算符
dynamic_cast 运算符

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • C++类型转换总结 本章内容:1 前言2 static_cast3 dynamic_cast4 const_cas...
    Haley_2013阅读 948评论 0 50
  • C++添加了四种类型转换运算符: 其中type-name表示转换后的类型,expresion表示被转换的表达式。 ...
    Tianql阅读 337评论 0 0
  • 这篇介绍C++的4种类型转换 dynamic_cast, static_cast, reinterpret_cas...
    CodingCode阅读 494评论 0 0
  • static_cast 用于类层次结构中,基类和子类之间指针和引用的转换。进行上行转换,也就是把子类的指针或引用转...
    第八区阅读 469评论 0 0
  • C++ 一共有4种类型转换方式,分别是: static_cast,dynamic_cast,const_cast,...
    wayyyy阅读 430评论 0 0