实例
class base
{
public:
base()
{}
~base()
{}
virtual void fun()
{
cout<<"base fun"<<endl;
}
};
class driver:public base
{
public:
driver()
{}
~driver()
{}
void fun()
{
cout<<"driver fun"<<endl;
}
};
一、派生类转基类
情形一:
driver dr;
base bs = dr;//正确,这里bs表示派生类(dr)中父类的那部分。
bs.fun();//输出base fun。这里仅仅是基类调用方法。虚函数的多态,是由指向派生类的基类指针或引用调用虚函数时,才会调用派生类重写的虚函数。这里并不是基类指针或引用。
dr.fun();//输出driver fun.
情形二:
driver dr;
base* bs = &dr;//用基类指针指向派生类。
bs->fun();//输出driver fun。这里就是虚函数多态的体现。
base& bs1 = dr;
bs1.fun();//输出driver fun。也是虚函数多态的体现
当基类指针或引用指向派生类时,如果派生类重写了基类的虚函数,那么该基类指针或引用调用虚函数时,调用的是子类重写的虚函数,如果子类没用重写,那么调用的就是父类自己的虚函数。
二、基类转为派生类
这是不被允许的,因为当基类转为派生类后,会有越界行为。
情形一:
base bs;
driver dr = bs;//编译出错。from 'base' to non-scalar type 'driver' requested 。类型不匹配错误
driver dr1 = (driver)bs;//使用强转,那么编译同样错误,没有匹配到driver::driver(base&)的构造函数。
所以基类对象是不允许转为派生类对象的。
情形二:
base* bs = new base();
driver* dr = bs;//错误,编译出错,invalid conversion from 'base*' to 'driver*'。
driver* dr1 = (driver*)bs;//这样编译没问题,但是存在越界访问风险。
三、使用dynamic_cast是c++操作符
dynamic_cast
是用来检查两者是否有继承关系。因此该运算符实际上只接受基于类对象的指针和引用的类转换
dynamic_cast < new_type > ( expression ) ;
class Base
{
public:
Base(){};
virtual void Show(){cout<<"This is Base calss";}
};
class Derived:public Base
{
public:
Derived(){};
void Show(){cout<<"This is Derived class";}
};
int main()
{
Base *base ;
Derived *der = new Derived;
//base = dynamic_cast<Base*>(der); //正确,但不必要。
base = der; //先上转换总是安全的
base->Show();
system("pause");
}
使用dynamic_cast向下转换时,需要(待转换的基类)基类含有虚函数,否则会编译出错。向上转换则不必有虚函数。
为什么说使用dynamic_cast是安全的?
因为dynamic_cast在向下转换时,会检查该基类指针是否是指向其派生类对象的,否则返回NULL;
说白了,就是检查待转换的指针或引用是否是指向要转换的类型的。