一、动态类型识别
1、问题引出
派生类指针指向基类对象
#include <iostream>
using namespace std;
class Parent
{
private:
int a;
};
class Child : public Parent
{
public:
int array[102400];
};
void f(Parent *p)
{
Child *c = (Child *) p; //派生类指针指向基类对象
c->array[102400 - 1] = 100; //不存在这块内存 因为只有4个字节
}
int main()
{
//Parent *p = new Child;
Parent *p = new Parent; //派生类指针指向基类对象
f(p);
delete p;
return 0;
}
2、动态对象类型识别概念
C++为了能够在运行时正确判断一个对象确切的类型,加入了RTTI(Run-Time Type Identification)。
RTTI提供了以下两个非常有用的操作符:
(1)typeid操作符,返回指针和引用所指的实际类型。
(2)dynamic_cast操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用。
三种办法可以解决C++动态类型识别问题。
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
{
private:
public:
enum{ID = 1};
int array[102400];
virtual int getid()
{
return ID;
}
};
void f(Parent *p)
{
//如果指针指向派生类对象,可以转换,指向基类对象,不可以转换
if(p->getid() == Child :: ID) //如果成立,说明指向派生类对象
{
Child *c = (Child *) p; //派生类指针指向基类对象
c->array[102400 - 1] = 100; //不存在这块内存 因为只有4个字节
}
else
{
cout << "不能转换" << endl;
}
}
int main()
{
// Parent *p = new Child; //基类变大
Parent *p = new Parent; //派生类指针指向基类对象
f(p);
delete p;
return 0;
}
4、关键字 dynamic_cast(相对温和的指针类型转换,只能有虚函数的类族)
1、dynamic_cast是C++中的新型关键字
2、dynamic_cast用于基类和派生类之间的转换
3、dynamic_cast要求使用的目标类型是多态的
即要求所在类族至少有一个虚函数
用于指针转换时,转换失败返回空指针
用于引用转换时,转换失败将引发bad_cast异常
dynamic_cast的优势
1、不用显示的声明和定义虚函数
2、不用为类族中的每个类分配类型ID
dynamic_cast的缺陷
1、只能用于有虚函数的类族
void f(Parent *p)
{
Child *c = dynamic_cast<Child *>(p); //如果p指向的是基类对象,则转换失败,转化失败,返回NULL
if(NULL == c)
{
cout << "转换失败" << endl;
}
else
c->array[102400 - 1] = 100; //不存在这块内存 因为只有4个字节
}
5、typeid关键字(不限定变量类型)
功能:返回变量的类型
包涵头文件typeinfo
#include <iostream>
#include <typeinfo>
using namespace std;
class Parent
{
private:
int a;
public:
void cs()
{
}
virtual void show()
{
cout << "hello" << endl;
}
};
class Child : public Parent
{
public:
int array[102400];
virtual void show()
{
}
};
void f(Parent *p)
{
if(typeid(*p) == typeid(Parent))
{
cout << "转换失败" << endl;
}
else if(typeid(*p) == typeid(Child))
{
Child *c = (Child *) p; //派生类指针指向基类对象
c->array[102400 - 1] = 100; //不存在这块内存 因为只有4个字节
}
}
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;
Parent *p = new Child;
//p->show();
f(p);
delete p;
return 0;
}
二、纯虚函数和抽象类
1、纯虚函数和抽象类
1、含有纯虚函数叫做抽象类 抽象类不能创建对象
2、virtual void print() = 0; //等于0的虚函数 没有函数体
3、衍生类必须实现纯虚函数。
#include <iostream>
using namespace std;
class Parent //含有纯虚函数叫做抽象类 抽象类不能创建对象
{
public:
void show()
{
cout << "this is parent" << endl;
}
virtual void print() = 0; //等于0的虚函数 没有函数体 //虚函数重写,参与动态联编,调用函数是确认真正变量类型
/*{
cout << "this is parent" << endl;
}*/
};
class Child : public Parent
{
public:
void print() //必须实现纯虚函数
{
cout << "this is Child" << endl;
}
};
int main()
{
Parent *p = new Child; //没有virtual关键字 不参与动态联编 默认是parent类型
p->print();
return 0;
}