c++子类和父类指针的转换
1.父类指针无法直接调用子类的新函数,需要转换为子类指针后才能调用。
c++编译器在编译的时候是做静态类型分析,父类指针是否真的指向一个子类类型,编译器并不会做这个假设。因此用父类的指针去调用子类的函数无非被识别,这里有一种安全和不安全的方式实现这种转化。
case1:不安全的方式
class Base { public: void vritual Func() { cout<<"Base Func "; } } class Child :public Base { public: void Func() { cout<<"Child Func "; } void NewFunc() { cout<<"Child Newfunc "; } } //测试用例
int main() { Base *b=new Child; b->Func();//输出Child Func //b->NewFunc();//错误 这个函数不是虚函数,不能多态调用 Child *child=(Child *)b;//方式一不安全 child->NewFunc();//Child NewFunc Child *child=dynamic_cast<Child *>(b);//方式二安全方式 if (child!=NULL) { child->NewFunc();//Child NewFunc } return 0; }备注:
1.方式一强制转换方式不安全
不安全是因为转换的时候无法得知是否转换成功。编译器强制把b当成Child类型去使用。比如说b本来是真的指向Base而不是Child类型那么强制转换后调用Child的NewFunc可能会导致程序崩溃。
2.方式二:动态转换方式
dynamic_cast是在运行时去做转换而非编译时,所以它可以给出是否转换成功的信息。如果转换不成功则返回NULL。所以可以判断转换结果是否为NULL来决定是否能使用该指针不会导致程序崩溃
转换情况二:
父类不存在虚函数:
#include <iostream> using namespace std; typedef void(*Fun)(void); class Base { public: Base(int i):a(i){b = 3;} void virtual fun() {cout << "Base"s funciton" <<endl;} void this_fun(Base *b) { if (b == this) cout << "it is Base"s this" <<endl; } private: int b; int a; }; class Derived: public Base { public: Derived():Base(2),d(0){} void fun() { cout << "Derived"s function" <<endl;} void this_fun(Derived *d) { if (d == this) cout << "it is Derived"s this" <<endl; } private: int d; };
int main() { Base b(1); Derived *d=(Derived*) &b; (*d).this_fun(d);//输出: it is Derived‘s 证明:d指针仍然为指向子类 cout<<*((int *)d)<<endl;//输出:Base 的成员b的值 3 证明:d指向的仍然为父类对象 cout<<*((int *)d+1)<<endl;// 输出:Base 的成员a 的值 1 证明:d指向的仍然为父类对象 d->fun();//d 为指向子类的指针 system("pause"); return 0; }注意:1. *((int *)d) 是将对象指针强转,访问第一个成员 ((int *)b+1)访问对象的第二个成员变量
int main() { Base b(1); Derived *d=(Derived*) &b; (*d).this_fun(d);//输出的:it is Derived"s this 证明:this指针仍然为指向子类 Fun f1=(Fun)*(int*)*(int *)d; //定义一个函数指针 值为d的虚函数 f1();//输出:Base’s function 证明:f1指向父类虚函数表的第一个函数 cout<<*((int *)d)<<endl;//输出:一个一个地址值 17384060 cout<<*((int *)d+1)<<endl;// 输出:Base 的成员b 的值 3 证明:d所指向的对象仍然为父类对象 cout<<*((int *)d+2) <<endl; //输出:Base的成员a 的值 1 证明:d所指向的对象仍然为父类对象 d->fun();//fun是虚函数,因此寻找虚函数表的第一个 system("pause"); return 0; }分析:
1.Fun f1=(Fun)*(int*)*(int *)d;
从右往左分析 (int *)d 转换为一个int 类型的指针,*(int *)d,获取指针所指的内容,其实存放的是地址, 即虚函数表地址(表第一项地址)
(int *)*(int *)d 地址强转一下,*(int *)*(int *)d,访问虚函数表的第一项,其实存放的也是指针,(Fun)强转为函数指针 ;
2.存在虚函数,此时对象布局发生改变
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。