C++父类、子类

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{…}。

 

const_cast操作符
其表达式为 const_cast<类型>(表达式),
 
其中类型指要把表达式转换为的目标类型。该操作符用于改变const和volatile,const_cast最常用的用途就是删除const属性,如果某个变量在大多数时候是常量,而在某个时候又是需要修改的,这时就可以使用const_cast操作符了。
const_cast操作符不能改变类型的其他方面,他只能改变const或volatile,即const_cast不能把int改变为double,但可以把const int改变为int。const_cast只能用于指针或引用。
 
const_cast的用法举例
比如:int a=3; const int *b=&a; int* c=const_cast(b); *c=4; cout<<a<<*c;这时输出两个4,如果不使用const_cast转换符则常量指针*c的值是不能改变的,在这里使用const_cast操作符,通过指针b就能改变常量指针和变量a的值。

 

 

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】免费获取数百本计算机经典书籍

    C++父类、子类

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/296283

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月15日 下午5:43
下一篇 2023年2月15日 下午5:44

相关推荐