父类指针在转换为子类指针的时候到底发生了什么?
父类指针在转换为子类指针的时候到底发生了什么?
class A
{
public:
void f()
{
cout<<"基类的f函数"<<endl;
}
virtual void h()
{
cout<<"基类的h函数"<<endl;
}
};
class B:public A
{
public:
void f()
{
cout<<"派生类的f函数"<<endl;
}
virtual void h()
{
cout<<"派生类的h函数"<<endl;
}
void g()
{
cout<<"派生类的g函数"<<endl;
}
};
int main()
{
A a;
B* pb = (B*)&a;
pb->f();//为什么输出派生类的f函数
pb->h();//为什么输出基类的g函数
pb->g();//为什么输出派生类的g函数
B b;
A* pa = &b;
pa->f();//为什么输出基类的f函数
pa->h();//输出派生类的h函数,这个能理解
return 0;
}
在这里,把父类a对象的地址赋给子类B类型的指针的时候,是怎么转换的呢?我想的是父类对象占用的内存空间比子类小,当将一个父类对象的地址赋给子类指针的时候,子类有而父类没有的内容,该怎么处理呢。。。求指导。
[解决办法]
本来是鹿,你说它是马,计算机就按照马去读取和解释它,至于会出什么问题,谁也不知道,只知道如果有麻烦,那一定是你自己的。。。。。。一般子类强制转父类还差不多
[解决办法]
?pb->f();//为什么输出派生类的f函数
/**
*member function call编译期resolve
*pb is a pointer to class object B, call B::f()
*/
??pb->h();//为什么输出基类的g函数
/**
*virtual function call执行期resolve
* pb->vfptr[1]()
* vfptr指向A类的虚表
*/
??pb->g();//为什么输出派生类的g函数
/**
*理由和调f()一样
*/
??B?b;
??A*?pa?=?&b;
??pa->f();//为什么输出基类的f函数
/**
*virtual function call执行期resolve
* pb->vfptr[1]()
* vfptr指向B类的虚表
*/
??pa->h();//输出派生类的h函数,这个能理解
[解决办法]
#include<iostream>
using namespace std;
class A { int a; };
class B { int b; };
class C : public A, public B { int c; };
int main()
{
C* ptr = new C();
cout<<"static_cast: "<<static_cast<A*>(ptr)<<", reinterpret_cast: "<<reinterpret_cast<A*>(ptr)<<endl;
cout<<"static_cast: "<<static_cast<B*>(ptr)<<", reinterpret_cast: "<<reinterpret_cast<B*>(ptr)<<endl;
}
[解决办法]
把子类指针强制转换为父类指针,还可以理解,这里把父类指针转换为子类指针就理解不了啊,想象的子类的内容比父类多,父类强转子类,那子类有而父类没有的东西该怎么办。。。然后把一个完全和类无关的整形变量的地址强制转换为类指针就更理解不了了。。。
有多重继承的时候你就知道能干什么用了。
有时候函数只接受基类指针参数(通常是基类虚函数),但是对于某个特定的继承类需要做一些特殊操作。这时候就需要判断基类指针是否指向那个特殊的继承类的实例,是的话进行转换,然后做特殊操作。
[解决办法]
几乎所有指针之间的强转,都只是改变对指针数据也就是地址的解读方式,不执行任何实际操作
例如一个指针指向类A的对象a,你要把它强制转换成指向类B的指针b,实际上这个强制转换没有执行复制四字节之外的任何操作,只是在你使用转换后的指针b时,编译器将按照类B的定义结构来计算成员变量地址偏移,对偏移后的地址读取并写入数据——至于实际上那个地址是否属于类A的对象a,编译器完全不在意
唯一的例外大概是派生类指针强制转换基类,单继承没什么可说的,多继承因为涉及到虚函数表指针,情形会比较复杂
如果楼主真的对这方面的知识比较感兴趣,可以去找一些专门的教材,例如编译原理,汇编语言等等
只在这里空想,你不可能得到正确答案,只会越想越错
[解决办法]
简单的说,编译器不负责类型检验,你说一个东西是什么,编译器就认为他是什么。
这个东西有利有弊,敝处就是乱用的话就会出错。而益处就是可以玩出很多花样。其实c里面最常见的一种用法是这样。
struct Head
{
int type;
}
struct Test1
{
Head h;
char * name;
int number;
};
struct Test2
{
Head h;
double price;
double delta;
};
这个时候你可以把指向Test2和Test1的指针都转化为指向Head的指针,需要的时候再根据type转换回来。
比如这样
if (head->type == 1) Test1 * t1 = (Test1*)head;
if (head->type == 2) Test2 * t2 = (Test2*)head;
如果你type的类型设错了,那就会发生内存越界,非法访问这样的错误。
[解决办法]
对于向下类型转换,虽然是不推荐的,但是有时候却不得不用!
GetDlgItem这个函数返回的是Cwnd*用的时候都是把返回值强转为Cbutton*
因为你知道那个控件就是一个CButton*, 所以可以这样用,也必须这样用。
MFC甚至SDK 提供了一系列机制用于这种情况,比如IsKindOf IsWindow 等等
但是,这都不是C++,乃至面向对象所钟爱的方式!
一旦使用了MFC,那就别无选择,只能继续这样使用;
你自己单独设计的代码,可以不这样用。
MFC系统的代码(继承自MFC的和使用MFC的代码),只有这样使用才行。