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;
}