1.父类指针无法直接调用子类的新函数,需要转换为子类指针后才能调用。
c++编译器在编译的时候是做静态类型分析,父类指针是否真的指向一个子类类型,编译器并不会做这个假设。因此用父类的指针去调用子类的函数无非被识别,这里有一种安全和不安全的方式实现这种转化。
case1:不安全的方式
-
class Base -
{ -
public: -
void vritual Func() -
{ -
cout<<"Base Func\n"; -
} -
} -
class Child :public Base -
{ -
public: -
void Func() -
{ -
cout<<"Child Func\n"; -
} -
void NewFunc() -
{ -
cout<<"Child Newfunc\n"; -
} -
} -
//测试用例
-
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.存在虚函数,此时对象布局发生改变


本文探讨了C++中父类指针如何安全地调用子类新增的方法。通过两种不同的转换方式——不安全的强制类型转换与安全的动态类型转换,解释了各自的原理及应用场景。
1万+

被折叠的 条评论
为什么被折叠?



