【C++笔记】十六、类型识别和转换

1.类型识别:dynamic_cast运算符

#include <iostream>
using namespace std;
class Biology
{
public:
    //  (涉及到多态问题)父类必须至少有一个虚方法,否则无法使用dynamic_cast进行类型转换
    virtual void process()
    {
        
    }
};

class Person:public Biology
{
public:
    int code = 200;
};

class Teacher : public Person
{
public:
    string name = "Bill";
};

int main(int argc, const char * argv[]) {
    // 类型识别:dynamic_cast运算符:转换指针/引用
    
    Biology *biology = new Biology();
    Biology *biology_person = new Person(); // 根据多态原则,这里有隐式的转换,Person()会自动继承Biology中的所有成员
    Biology *biology_teacher = new Teacher(); // 同上,进行了隐式转换,biology_teacher 由Teacher()创建,但指向Biology类
    
    Teacher *teacher1 = (Teacher*)biology_teacher;  // 安全的,将指针biology_teacher转换成指向Teacher的指针并赋值给新的变量teacher1
   // 对于下式而言,等号右侧是左侧的父类,即:是biology对象的,不一定是teacher2,所以类型转换不安全
    Teacher *teacher2 = (Teacher*)biology;          //  不安全的
    cout << teacher2->name << endl; // 什么也不会打印
    
   // 对于下式来说,等号右侧是等号左侧的子类,即凡是teacher对象的,一定是person,所以类型转换安全
    Person *person = (Teacher*)biology_teacher;    // 安全的,biology_teacher是由Teacher创建的、指向Biology类,(Teacher*)将biology_teacher转换成指向Teacher类,person指向Person类,二者能否划等号?能!因为teacher是person的子类,是teacher就一定是person,一定能指过去
   // dynamic_cast后面的尖括号里存放要转换成的目标类型,圆括号里存放要转换的变量
    Teacher *teacher3 = dynamic_cast<Teacher*>(biology_teacher);
    cout << "teacher3 address: " << teacher3 << endl; // 正常打印地址
    
    Teacher *teacher4 = dynamic_cast<Teacher*>(biology);
    cout << "teacher4 address: " << teacher4 << endl; // 打印0x0,转换失败,返回了空指针,后面可以通过判断返回值看出转换结果
    
    if(teacher4 != nullptr)
    {
        // ...
    }
    else
    {
        cout << "teacher4类型转换失败." << endl;
    }
    return 0;
}

2.dynamic_cast与引用类型转换

#include <iostream>
using namespace std;

class ParentClass
{
public:
    virtual void process()
    {
        cout << "parentclass" << endl;
    }
};

class SubClass : public ParentClass
{
public:
    virtual void process()
    {
        cout << "subclass" << endl;
    }
};

class MyClass
{
public:
    virtual void process()
    {
        cout << "myclass" << endl;
    }
};
int main(int argc, const char * argv[]) {
    // dynamic_cast与引用类型转换
    //  进行引用类型转换,通常需要使用try...catch捕获bad_cast异常
    
   // dynamic_cast的括号里的参数必须是引用类型的值
   // ParentClass parentClass = SubClass();
   // SubClass &subClass = dynamic_cast<SubClass&>(parentClass);  //  error:bad_cast
    
    SubClass subClass1;
    ParentClass &parentClass = subClass1; // 给subClass1起了一个ParentClass类型的别名parentClass
    SubClass &subClass2 = dynamic_cast<SubClass&>(parentClass);  // ParentClass类型的parentClass想通过dynamic_cast把自己的类型转换成SubClass
    subClass2.process(); // 打印 subclass,因为dynamic_cast将ParentClass类型的引用转换成了SubClass类型的引用
    
    MyClass myClass1;
    MyClass &myClass2 = myClass1;
    try
    {
        SubClass &subClass3 = dynamic_cast<SubClass&>(myClass2);  // 抛出异常
    }
    catch(exception &e)
    {
        cout << e.what() << endl;
    }
       
    return 0;
}

3.类型识别:typeid运算符

#include <iostream>
#include <typeinfo>
using namespace std;

class Biology
{
public:
   
    virtual void process()
    {
        
    }
};

class Person:public Biology
{
public:
    int code = 200;
};

class Teacher : public Person
{
public:
    string name = "Bill";
};

int main(int argc, const char * argv[]) {
    // 类型识别:typeid运算符,用来判断某个变量是不是由某个类创建的
    cout << "typeid(Biology).name() = " << typeid(Biology).name() << endl; // 7Biology,name()返回的值肯定会包含类名,其他的前缀后缀是随机的
    cout << "typeid(Teacher).name() = " << typeid(Teacher).name() << endl; // 7Teacher

    Teacher teacher1;    
    Teacher *teacher2 = new Teacher();
    if(typeid(Teacher) == typeid(teacher1))
    {
        cout << "typeid(Teacher) == typeid(teacher1)" << endl; // 输出"typeid(Teacher) == typeid(teacher1)"
    }
    //  typeid的参数值必须是对象,不能是对象指针
    if(typeid(Teacher) == typeid(*teacher2)) // 这里指针teacher2前面要加*
    {
        cout << "typeid(Teacher) == typeid(*teacher2)" << endl;// 输出"typeid(Teacher) == typeid(teacher1)"
    }
    
    Biology *biology = new Person();
    Person *person = nullptr;
    if(typeid(Person) == typeid(*biology)) // 如果二者相等,则说明biology是通过Person创建的,但指向Biology类
    {
        cout << "typeid(Person) == typeid(biology)" << endl; //打印typeid(Person) == typeid(biology)
        person = (Person*)biology; // biology是由Person类创建的,所以才能转换,这句话让biology指向了Person类,不再指向Biology类
        cout << person->code << endl;  // 200
    }
    
    Person *p;
    try
    {
       typeid(*p); // 如果此时p是空指针,那么typeid会抛出异常
    }
    catch(exception &e)
    {
        cout << e.what() << endl;
    }
  
    return 0;
}

4.类型转换运算符概述

#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
	
    // 类型转换操作符(运算符)概述
    //  dynamic_cast<<#type#>>(<#expression#>):可以进行任何类型的转换
    //  const_cast<<#type#>>(<#expression#>):type和expression的类型必须相同,但是可以去掉const或volatile
    //  static_cast<<#type#>>(<#expression#>):type必须可隐式转换为expression,type是expression的子类,
    //  reinterpret_cast<<#type#>>(<#expression#>):进行特殊类型的转换。例如,将一个long类型的值转换为指针类型
    
    return 0;
}

5.const_cast运算符

#include <iostream>
using namespace std;
class MyClass1
{
public:
    virtual void process(){}
};
class MyClass2
{
    
};
int main(int argc, const char * argv[]) {
    // 类型转换运算符:const_cast
    MyClass1 *pMyClass1_1 = new MyClass1();
    const MyClass1 *pMyClass1_2 = const_cast<MyClass1*>(pMyClass1_1); //将pMyClass1_1转换成常量指针
    
    MyClass1 *pMyClass1_3 = const_cast<MyClass1*>(pMyClass1_2); // 将常量指针pMyClass1_2转换成普通指针
    
   // MyClass2 *pMyClass2 = const_cast<MyClass2*>(pMyClass1_1);    // error
    
    MyClass1 myClass1_1;
    MyClass1 &myClass1_2 = myClass1_1;  
    const MyClass1 myClass1_3 = const_cast<MyClass1&>(myClass1_2); // 引用类型变量的转换

    return 0;
}

6.static_cast运算符

#include <iostream>
using namespace std;
class ParentClass
{
public:
    virtual void process()
    {
        
    }
};
class SubClass : public ParentClass
{
    
};
class MyClass
{
    
};

int main(int argc, const char * argv[]) {
    // 类型转换运算符:static_cast
    ParentClass *parentClass = new SubClass();//指针parentClass由SubClass创建,但指向ParentClass类,这种情况,parentClass可以转而指向ParentClass类的变量
    SubClass *subClass = static_cast<SubClass*>(parentClass);
    
    MyClass *myClass = new MyClass();
   // SubClass *subClass1 = static_cast<SubClass*>(myClass);  //  error
    return 0;
}

7.reinterpret_cast运算符

#include <iostream>
using namespace std;
class MyClass
{
public:
    virtual void process()
    {
        cout << "MyClass" << endl;
    }
};
int main(int argc, const char * argv[]) {
    // 类型转换运算符:reinterpret_cast
    MyClass myClass;
    cout << "myClass的地址(Hex)"  << &myClass << endl; // 打印十六进制的地址
    
// long myClass_address = &myClass,这在C语言中是可以的,但在C++中是不能这样做的,要用reinterpret_cast
    long myClass_address = reinterpret_cast<long>(&myClass); // 用long类型存储地址值
    cout << "myClass_address(Dec) = " << myClass_address << endl; // 打印十进制的地址
    cout << "myClass_address(Hex) = 0x" << hex << myClass_address << endl; // 加了hex表示后面的值都以十六进制输出,打印十六进制的地址
    
    MyClass *pMyClass = reinterpret_cast<MyClass*>(myClass_address); // 将myClass_address转换成了指向MyClass类的指针

    pMyClass->process();
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DUANDAUNNN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值