11.1 动态类识别
11.1.1 自定义类型
-
C++中的多态根据实际的对象类型调用对应的函数
(1)可以在基类中定义虚函数返回具体的类型信息
(2)所有的派生类都必须实现类型相关的虚函数
(3)每个类中的类型虚函数都需要不同的实现
-
使用虚函数进行动态类型识别的缺陷
(1)必须从基类开始提供类型虚函数
(2)所有派生类都必须重写类型虚函数
(3)每个派生类的ID必须唯一
示例代码:
#include <iostream>
using namespace std;
class Parent
{
private:
int a;
public:
enum {ID = 0};
virtual int getID()
{
return ID;
}
};
class Child : public Parent
{
public:
enum {ID = 1};
int array[102400];
virtual int getID()
{
return ID;
}
};
void f(Parent *p)
{
//Child *c = (Child *)p; //派生类指针指向基类对象 //如果指针指向派生类对象,可以转换,指向基类对象,不能转换
if (p->getID() == Child::ID) //如果成立,说明指向派生类对象
{
Child *c = (Child *)p;
c->array[102400 - 1] = 100;
}
else
{
cout << "不能转换" << endl;
}
}
int main()
{
//Parent *p = new Child;
Parent *p = new Parent;
f(p);
return 0;
}
运行结果:
11.1.2 dynamic_cast
-
新的关键字 dynamic_cast
(1)dynamic_cast是C++中的新型关键字
(2)dynamic_cast用于基类和派生类之间的转换
(3)dynamic_cast要求使用的目标类型是多态的
即要求所在类族至少有一个虚函数
用于指针转换时,转换失败返回空指针
用于引用转换时,转换失败将引发bad_cast异常 -
dynamic_cast的优势
(1)不用显示的声明和定义虚函数
(2)不用为类族中的每个类分配类型ID -
dynamic_cast的缺陷
只能用于有虚函数的类族
示例代码:
#include <iostream>
using namespace std;
class Parent
{
private:
int a;
public:
virtual void show()
{}
};
class Child : public Parent
{
public:
int array[102400];
void show()
{}
};
void f(Parent *p)
{
Child *c = dynamic_cast<Child *>(p); //如果p指向的是基类对象,则转换失败,转换失败返回NULL
if (NULL == c)
{
cout << "转换失败" << endl;
}
else
{
cout << "转换成功" << endl;
c->array[102400 - 1] = 100;
}
}
int main()
{
//Parent *p = new Child;
Parent *p = new Parent;
f(p);
return 0;
}
运行结果:
11.1.3 typeid
- C++提供了typeid关键字用于动态获取类型信息
(1)typeid关键字返回对应参数的类型信息
(2)typeid关键字返回一个type_info类对象,当typeid参数为NULL时,抛出bad_typeid异常
(3)type_info类的使用需要包含typeinfo头文件 - typeid的使用
示例代码:
#include <iostream>
#include <typeinfo>
using namespace std;
class Parent
{
private:
int a;
public:
virtual void show()
{
}
};
class Child : public Parent
{
public:
int array[102400];
public:
void show()
{
}
};
void f(Parent *p)
{
if (typeid(*p) == typeid(Child))
{
cout << "可以转换" << endl;
Child *c = (Child *)p; //派生类指针指向基类对象
c->array[102400 - 1] = 100;
}
else if (typeid(*p) == typeid(Parent))
{
cout << "不能转换" << endl;
}
}
int main()
{
int a;
char ch;
Parent p1;
Child c1;
const type_info &pa = typeid(a);
const type_info &pch = typeid(ch);
const type_info &pp1 = typeid(p1);
const type_info &pc1 = typeid(c1);
cout << pa.name() << endl;
cout << pch.name() << endl;
cout << pp1.name() << endl;
cout << pc1.name() << endl;
//if (pa.name() == i) // 不同编译器可以不一样(不能这么写)
Parent *p = new Parent;
//Parent *p = new Child;
f(p);
return 0;
}
运行结果:
11.2 纯虚函数和抽象类
11.2.1 基本概念
- 抽象类
(1)含有纯虚函数的类;
(2)抽象类不能用于直接创建对象实例,可以声明抽象类的指针和引用
(3)可使用指向抽象类的指针支持运行时多态性
(4)派生类中必须实现基类中的纯虚函数,否则它仍将被看作一个抽象类
示例代码:
#include <iostream>
using namespace std;
class Parent //含有纯虚函数的类称为抽象类 抽象类不能创建对象
{
public:
void show()
{
cout << "this is parent" << endl;
}
virtual void print() = 0; //纯虚函数 没有函数体
};
class Child : public Parent
{
public:
void print()
{
cout << "this is Child" << endl;
}
};
int main()
{
//Parent pp;
//pp.print();
Parent *p = new Child;
p->print();
return 0;
}
运行结果: