C++--第27课 - 动态类型识别

第27课 - 动态类型识别

问题:下面的程序有问题吗?

class Parent

{

public:

virtual -Parent()

{

}

};

class Child : public Parent

{

};

void test(Parent* p)

{

Child* c = (Child*)p;  //将父类强制转化为子类

}

1. 动态类型

由于基类指针可以直接指向派生类对象,因此可能存在指针所指类型与具体指向的对象类型不同的情况。

(p指向的静态类型为Parent)Parent* p = new Child();(p实际指向的对象类型为Child)

动态类型指的是基类指针所指向的对象的实际类型

void test(Parent* p)

{

Child* c = (Child*)p; //当p的动态类型为Child时,转换成功

//否则,可能出现无法预知的错误

}

基类指针是否可以强制类型转换为子类指针取决于动态类型!

C++中如何得到动态类型?

2. 动态类型识别

C++中的多态根据实际的对象类型调用对应的虚函数

(1)      可以在基类中定义虚函数返回具体的类型信息。

(2)      所有的派生类都必须实现类型相关的虚函数。

(3)      每个类中的类型虚函数都需要不同的实际。

利用多态进行动态类型识别

#include <cstdlib>

#include <iostream>

using namespace std;

class Parent

{

public:

enum { ID = 0 };

virtual int type()  //自动变成虚函数,类型虚函数

{

return ID;

}

};

class Child : public Parent

{

public:

enum { ID = 1 };

int type()      //自动变成虚函数virtual,类型虚函数

{

return ID;

}

int add(int a, int b)

{

return a + b;

}

};

void test(Parent* p)

{

if( p->type() == Child::ID )

{

Child* c = (Child*)p;

cout<<"Dynamic Type: "<<"Child"<<endl;

cout<<"add: "<<c->add(2, 3)<<endl;

}

if( p->type() == Parent::ID )

{

cout<<"Dynamic Type: "<<"Parent"<<endl;

}

}

int main(int argc, char *argv[])

{

Parent parent;

Child child;

test(&parent);

test(&child);

cout << "Press the enter key to continue ...";

cin.get();

return EXIT_SUCCESS;

}

运行结果:

Dynamic Type: Parent

Dynamic Type: Child

add: 5

使用虚函数进行动态类型识别的缺陷:

1)         必须从基类开始提供类型虚函数。

2)         所有的派生类都必须重写类型虚函数。

3)         每个派生类的类型ID必须唯一。

利用函数进行动态类型识别的方法可以满足工程的需要,但是维护性会随着派生类的增多而成指数级增加。

改进:

在头文件中加入#include<string>,虚函数中返回return “Child”;return “Parent”;在后面的判断语句中,用if(strcmp(p->type90,”Child”)==0)来判断,就会得到我们上面一样的结果。但是这里面的维护性好了,但是效率会变得更低,所以这种方式,也不好。也就是凡是使用多态就会出现问题。个人倾向于使用ID。我们看一下下面的新方法。

新的关键字dynamic_cast

(1)      dynamic_cast是C++中的新型转换关键字。

(2)      dynamic_cast主要用于基类和派生类之间的转换。

(3)      dynamic_cast要求使用的目标对象类型是多态的。

即:所在类族至少有一个虚函数

用于指针转换时,转换失败返回空指针;用于引用转换时,转换失败将引发bad_cast异常。凡是转换成功就会是原来的指针。

利用dynamic_cast进行动态类型识别

#include <cstdlib>

#include <iostream>

using namespace std;

class Parent

{

public:

virtual ~Parent()

{

}

};

class Child : public Parent

{

public:

int add(int a, int b)

{

return a + b;

}

};

class NewChild : public Parent

{

};

void test(Parent* p)

{

Child* c = dynamic_cast<Child*>(p);

if( c != NULL )

{

cout<<"Dynamic Type: "<<"Child"<<endl;

cout<<"add: "<<c->add(2, 3)<<endl;

}

else

{

if( dynamic_cast<NewChild*>(p) != NULL )

{

cout<<"Dynamic Type: "<<"NewChild"<<endl;

}

else

{

cout<<"Dynamic Type: "<<"Parent"<<endl;

}

}

}

int main(int argc, char *argv[])

{

Parent parent;

Child child;

NewChild nc;

test(&parent);

test(&child);

test(&nc);

cout << "Press the enter key to continue ...";

cin.get();

return EXIT_SUCCESS;

}

运行结果:

Dynamic Type: Parent

Dynamic Type: Child

add: 5

Dynamic Type: NewChild

dynamic_cast是优势

不用显示的声明和定义类型虚函数

不用为类族中的每个类分配类型ID

dynamic_cast的缺陷

只能用于具有虚函数的类族

使用dynamic_cast进行动态类型识别可以取代类型虚函数的方案,但是在本质上dynamic_cast还是需要类族中存在虚函数(在工程上常把析构函数作为这个虚函数定义)。

C++中是否可以得到任意类型的类型信息呢?

C++提供了typeid关键字用于动态获取类型信息

typeid关键字返回对应参数的类型信息。这是专门为动态类型识别提供的关键字。

typeid返回一个type_info类对象:当typied的参数为NULL时,抛出bad_typied异常。

type_info类的使用需要包含<typeinfo>

class type_info

{

public:

virtual ~type_info();

bool operator==(const type_info& rhs);

bool operator!=(const type_info& rhs);

int before(const type_info& rhs);

const char* name();

};

typeid关键字的使用

#include <cstdlib>

#include <iostream>

#include <typeinfo>

using namespace std;

class Parent

{

public:

virtual ~Parent()

{

}

};

class Child : public Parent

{

public:

int add(int a, int b)

{

return a + b;

}

};

class NewChild : public Parent

{

};

void test(Parent* p)

{

if( typeid(*p) == typeid(Child) )

{

Child* c = dynamic_cast<Child*>(p);  //结合上面的思想,两个关键字都用。

cout<<"Dynamic Type: "<<"Child"<<endl;

cout<<"add: "<<c->add(2, 3)<<endl;

}

else if( typeid(*p) == typeid(NewChild) )

{

cout<<"Dynamic Type: "<<"NewChild"<<endl;

}

else if( typeid(*p) == typeid(Parent) )

{

cout<<"Dynamic Type: "<<"Parent"<<endl;

}

}

int main(int argc, char *argv[])

{

Parent parent;

Child child;

NewChild nc;

int index;

char ch;

const type_info& tp = typeid(parent);

const type_info& tc = typeid(child);

const type_info& tn = typeid(nc);

const type_info& ti = typeid(index);

const type_info& tch = typeid(ch);

cout<<tp.name()<<endl;

cout<<tc.name()<<endl;

cout<<tn.name()<<endl;

cout<<ti.name()<<endl;

cout<<tch.name()<<endl;

test(&parent);

test(&child);

test(&nc);

cout << "Press the enter key to continue ...";

cin.get();

return EXIT_SUCCESS;

}

运行结果:

6Parent

5Child

8NewChild

i

c

Dynamic Type: Parent

Dynamic Type: Child

add: 5

Dynamic Type: NewChild

分析:

typeid是一个与编译器实现相关的关键字,在有的编译器中是不支持的。我们看到的结果在不同的编译器中是不一样的。

小结:

C++可以通过多态的方式进行动态类型识别。

dynamic_cast关键字是可用动态类型识别。

typeid关键字在C++中专用于动态类型的识别。

原文地址:https://www.cnblogs.com/free-1122/p/11336323.html

时间: 2024-10-10 08:08:10

C++--第27课 - 动态类型识别的相关文章

Objective-C多态:动态类型识别+动态绑定+动态加载

一.Objective-C多态 1.概念:相同接口,不同的实现 来自不同类可以定义共享相同名称的方法. 动态类型能使程序直到执行时才确定对象所属类型 动态类型绑定能使程序直到执行时才确定要对对象调用的实际方法 2.Objective-C不同于传统程序设计语言,它可以再运行时加入新的数据类型和新的程序模块:动态类型识别,动态绑定,动态加载 3.id类型:通用指针类型,弱类型,编译时不进行类型检查 二.动态类型识别 1.任意NSObject的子类都会继承NSObject的isa实例变量,而且当NSO

动态类型识别&amp;动态创建

以下大部分内容摘自<windows程序设计 第2版> 王艳平 张铮 编著 动态类型识别:在程序运行过程中,辨别对象是否属于特定类的技术. 应用举例:函数辨别参数类型.需要针对对象的类编写特定的代码. CRuntimeClass 包含类信息(不仅包含一般的信息,还包括创建类的函数指针) #include <iostream> #include<windows.h> using namespace std; /////////////////////////////////

第66课 C++中的类型识别

1. 类型识别 (1)在面向对象中可能出现下面的情况 ①基类指针指向子类对象 ②基类引用成为子类对象的别名 ▲静态类型——变量(对象)自身的类型(定义变量类型时类型或参数类型) ▲动态类型——指针(引用)所指向的对象的实际类型 (2)基类指针转子类指针: ①示例:Derived* d = static_cast<Derived*>(pBase); //危险的转换方式 ②问题:不安全,是否能强制类型转换取决动态类型. 2. 利用多态获取动态类型 (1)解决方案 ①在基类中定义虚函数,并返回具体的

C++中的类型识别

1.C++中类型识别 (1)在面向对象中可能出现下面的情况 @1:基类指针指向子类对象 Base *p = new child(); @2:基类引用成为子类对象的别名 Base& r = *p; --上面的base是基类,child是这个基类的子类,第一种情况,由于赋值兼容性的存在,父类指针是可以指向子类对象的,但是我们无法通过父类指针来知道当前指针指向的是否是子类对象. --但是这时我们可以说,指针p的静态类型是Base*(指针期望的类型),指针p的动态类型是child(因为这时指针p指向的类

MFC六大核心机制之二:运行时类型识别(RTTI)

上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属于某个类,我们平时用C++编程接触的RTTI一般是编译器的RTTI,即是在新版本的VC++编译器里面选用“使能RTTI”,然后载入typeinfo.h文件,就可以使用一个叫typeid()的运算子,它的地位与在C++编程中的sizeof()运算子类似的地方(包含一个头文件,然后就有一个熟悉好用的函数

OC 动态类型和静态类型

多态 允许不同的类定义相同的方法 动态类型 程序直到执行时才能确定所属的类 静态类型 将一个变量定义为特定类的对象时,使用的是静态形态 将一个变量定义为特定类的对象时,使用的是静态类型,在编译的时候就知道这个变量所属的类,这个变量总是存储特定类的对象.使用静态类型时,编译器尽可能的确保变量的用法在程序中始终保持一致,编译器能够通过检查来确定应用于对象的方法是由该类定义的或者由该类继承的,否则就会显示警告,静态类型能够更好地在程序编译阶段就指出错误.并且使用静态类型可以提高程序的可读性 简单来说:

类型识别(五十四)

我们在面向对象中可能会出现这样的情况:基类指针指向子类对象.基类引用成为子类对象的别名.如下 静态类型便指的是变量(对象)自身的类型,动态类型是指指针(引用)所指向对象的实际类型.基类指针是否可以强制类型转换为子类指针取决于动态类型!下面的这种转换方式是危险的 那么我们在 C++ 中如何得到动态类型呢?解决方案便是利用多态:1.在基类中定义虚函数返回具体的类型信息:2.所有的派生类都必须实现类型相关的虚函数:3.每个类中的类型虚函数都需要不同的实现. 下来我们就用代码来分析 #include <

C++解析(29):类型识别

0.目录 1.类型识别 2.动态类型识别 3.类型识别关键字 4.小结 1.类型识别 在面向对象中可能出现下面的情况: 基类指针指向子类对象 基类引用成为子类对象的别名 静态类型--变量(对象)自身的类型 动态类型--指针(引用)所指向对象的实际类型 2.动态类型识别 C++如何得到动态类型? 解决方案--利用多态: 在基类中定义虚函数返回具体的类型信息 所有的派生类都必须实现类型相关的虚函数 每个类中的类型虚函数都需要不同的实现 示例--利用多态动态类型识别: #include <iostre

C++杂记:运行时类型识别(RTTI)与动态类型转换原理

运行时类型识别(RTTI)的引入有三个作用: 配合typeid操作符的实现: 实现异常处理中catch的匹配过程: 实现动态类型转换dynamic_cast. 1. typeid操作符的实现 1.1. 静态类型的情形 C++中支持使用typeid关键字获取对象类型信息,它的返回值类型是const std::type_info&,例: #include <typeinfo> #include <cassert> struct B {} b, c; struct D : B {