C++强制类型转换
1,父类和子类的关系
介绍
先有父类,再有子类,先析构子类,再析构父类
第一,子类对象在创建时会首先调用父类的构造函数
第二, 父类构造函数执行结束后,执行子类的构造函数
第三, 当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
第四, 析构函数调用的先后顺序与构造函数相反
继承的概念:面向对象中的继承指类之间的父子关系, 子类拥有父类的某些状态和行为,(子类复用了父类的功能或状态)。
继承有三种:public,protect,private
1:如果父类中的成员使用public修饰,子类无条件继承。需要被外界访问的成员直接设置为public
2:如果父类中的成员使用protected修饰,子类也继承,即使父类和子类不在同一个包中。 protected成员可以在本类和子类中被访问,但不能在外界被访问,访问权限介于public和private之间。
3:如果父类和子类在同一个包中,此时子类可以继承父类中缺省修饰符的成员。
4:如果父类中的成员使用private修饰,子类打死也都继承不到。private只能在本类中访问。
5:父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同。
3.c++中的访问级别与继承:
a. 继承时的访问级别设定会影响到成员的访问级别,c++中class的默认继承为private继承
b. private继承的子类拥有父类的所有成员,private继承使得父类的所有成员在子类中变成private成员
如:class test1:private test{}
c. public继承,父类成员在子类中保持原有访问权限。private继承,父类成员在子类中变成为private成员。protected继承,父类中访问权限比protected高的,保持原有权限,其余的访问权限变成protected。
d. 最常用的继承方式为,public继承。类的成员常用protected属性和public属性。
子类与父类中的同名成员变量:
a.当子类成员变量与父类成员变量同名时, 子类依然从父类继承同名成员
b. 在子类中通过作用域分别符号 :: 进行同名成员区分
c. 同名成员存储在内存中的不同位置
d. 如果在子类中不用作用域分别符号:: 区分同名成员变量,默认的成员变量是子类的成员变量
作用
如果多个子类需要继承同一个父类中的成员,则可以写一个父类实现子类们共同的功能,然后各个子类不同的功能可以在各自子类中完成。
2,强制转换介绍
dynamic_cast 用于多态类型的转换(泛指有虚函数的类类型)
static_cast 用于非多态类型的转换(指所有的其他类型。 )
const_cast 用于删除 const、volatile 和 __unaligned 特性
reinterpret_cast 用于位的简单重新解释
static_cast操作符
用法:static_cast < type-id > ( expression_r_r )
该运算符把expression_r_r转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
用于类层次结构中基类和子类之间指针或引用的转换。进行上行转换(把子类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
把空指针转换成目标类型的空指针。
把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression_r_r的const、volitale、或者__unaligned属性。
dynamic_cast操作符
用法:dynamic_cast < type-id > ( expression_r_r )
该运算符把expression_r_r转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是类指针类型,那么expression_r_r也必须是一个指针,如果type-id是一个引用,那么expression_r_r也必须是一个引用。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
注意:dynamic_cast转换操作符在执行类型转换时首先将检查能否成功转换,如果能成功转换则转换之,如果转换失败,如果是指针则反回一个0值,如果是转换的是引用,则抛出一个bad_cast异常,所以在使用dynamic_cast转换之间应使用if语句对其转换成功与否进行测试,比如pd = dynamic_cast(pb); if(pd){…}else{…},或者这样测试if(dynamic_cast(pb)){…}else{…}。
3,实际代码测试
- 编程中需要将一个父类指针转换成子类指针,static_cast与dynamic_cast都可以成功。
例子
1 class B {}; 2 class D : public B {}; 3 void f(B* pb, D* pd) { 4 D* pd2 = static_cast<D*>(pb); // not safe, pb may point to just B 5 B* pb2 = static_cast<B*>(pd); // safe conversion 6 }
- 第一个转换就是危险的,如果pb指向的是B类的对象,将它强制转换成派生类D的指针pd2,若使用pd2调用派生类D独有的方法,就会出问题,建议不要父类转子类。
1 / static_cast_Operator_2.cpp 2 // compile with: /LD /GR 3 class B { 4 public: 5 virtual void Test(){} 6 }; 7 class D : public B {}; 8 void f(B* pb) { 9 D* pd1 = dynamic_cast<D*>(pb); 10 D* pd2 = static_cast<D*>(pb); 11 }
- 如果pb真的指向B类对象,pd1和pd2值一样;如果pb指向D类对象,pd1 == NULL,pd2可能被转换成指向D类的指针,因为dynamic_cast有动态类型检查。
1 // static_cast_Operator_3.cpp 2 // compile with: /LD /GR 3 typedef unsigned char BYTE; 4 void f() { 5 char ch; 6 int i = 65; 7 float f = 2.5; 8 double dbl; 9 ch = static_cast<char>(i); // int to char 10 dbl = static_cast<double>(f); // float to double 11 i = static_cast<BYTE>(ch); 12 }
- 多字节转换成少字节类型是有风险的,你自己要知道是否有截断风险,有的话转换结果未知。
- static_cast不能改变对象的const、volatile、__unaligned 属性。
- 若你是用release模式编译,想验证static_cast转换是否正确就要到debug模式下看看结果是否一致。
总结:
- 在类层次的上行转换(子类->父类)中,static_cast和dynamic_cast效果一样;在类层次的下行转换中(父类->子类),dynamic_cast更安全;
- dynamic_cast适用局限性,仅适用指针或引用,类型转换是额外开销;static_cast适用于所有,无类型检查额外开销。
- dynamic_cast要检查转换后指针情况,是否为空;static_cast不需要,但是要心中有数。
4,类型检查(实现c#中的is关键字)
方法一:使用dynamic_cast操作符进行类型检查
1 假设只有两个类Base和Derived,可以使用 2 if (dynamic_cast<Derived>(pClass) != NULL) 3 ...指向的是Derived 4 else 5 ...指向的是Base
方法二:如果拥有多个类,这种方法会变得较为复杂。可以使用typeid关键字
1 #include <iostream> 2 using namespace std; 3 4 class Object 5 { 6 }; 7 8 int main() 9 { 10 Object obj; 11 cout << "type name:" << typeid(obj).name() << endl; 12 cout << "type raw name:" << typeid(obj).raw_name() << endl; 13 if(typeid(obj) == typeid(Object)) 14 { 15 cout << "type is equal" << endl; 16 } 17 else 18 { 19 cout << "type is not equal" << endl; 20 } 21 return 0; 22 }
1 #include <string.h> 2 #include <typeinfo.h> 3 #include <stdio.h> 4 5 class Base 6 { 7 public: 8 Base() 9 { 10 strcpy(name,"Base"); 11 } 12 13 virtual void display() 14 { 15 cout<<"Display Base."<<endl; 16 } 17 18 virtual void printName() 19 { 20 printf("printf base\n"); 21 } 22 23 protected: 24 char name[64]; 25 }; 26 27 class Child1:public Base 28 { 29 public: 30 Child1() 31 { 32 strcpy(name,"Child1"); 33 } 34 35 void display() 36 { 37 cout<<"Display Child1."<<endl; 38 } 39 40 virtual void printName() 41 { 42 Base::printName(); 43 printf("printf Child1\n"); 44 } 45 }; 46 47 class Child2:public Base 48 { 49 public: 50 Child2() 51 { 52 strcpy(name,"Child2"); 53 } 54 55 void display() 56 { 57 cout<<"Display Child2."<<endl; 58 } 59 60 virtual void printName() 61 { 62 Base::printName(); 63 printf("printf Child2\n"); 64 } 65 }; 66 67 void Process(Base *type) 68 { 69 if( (typeid(Child1)) == (typeid(*type)) ) 70 { 71 ((Child1*)type)->display(); 72 printf("Process name = %s\n", typeid(*type).name()); 73 } 74 else if( (typeid(Child2)) == (typeid(*type)) ) 75 { 76 ((Child2*)type)->display(); 77 printf("Process name = %s\n", typeid(*type).name()); 78 } 79 else 80 { 81 cout<<"Unknow type!"<<endl; 82 } 83 }
原文链接: https://www.cnblogs.com/xiaoyaobing/p/10983806.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/296283
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!