为什么类指针从父类到子类会发生改变?

gamenewage 2004-11-29 02:32:37
我定义了三个类,分别是
class ClassA
class ClassB
class ClassC : public ClassB,public ClassA
三个类中都定义有自己的变量。
其中在ClassA中有一个ClassA指针。我试图在其中保存另一个ClassC对象的地址。可是当我在读取这个地址的时候,在ClassA的接口函数里面用ClassA到ClassC的强制类型转换,其结果得到的地址已经跟以前的不一样。就在我的眼前,在=号的前后竟然不一样。
同样,反过来,在我试图删掉这个指针的时候,我在接口里面先判断两个指针是否一样,需要传递另一个ClassC对象的地址,在外部调用ClassA接口的时候,传递的指针又从ClassC强制类型转换成ClassA,同样也发生了变化。难道系统自作聪明的给我加(减)上了ClassB的大小?可是我不管把它当成ClassA还是ClassC访问其中的数据仍然有错。
请教各位,这是怎么回事?我该怎么做?
...全文
394 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
gamenewage 2004-12-02
  • 打赏
  • 举报
回复
大概知道是怎么回事了。深入地了解也不是马上就能做到的。感谢各位了!
要说我的意图,仔细看应该看得出来,要真是不明白,我也没有说下去的必要了。
结分。
lifezhu 2004-12-01
  • 打赏
  • 举报
回复
你的意思就是ClassA具有自集合功能
static std::set<CClassA*> s_self_set yes?
lifezhu 2004-12-01
  • 打赏
  • 举报
回复
pClass和pClassTrue肯定相等
classC1.m_pClass肯定不一样
原因很简单
m_pClass是CClassA*
pClass和pClassTrue是CClassC*
结束
gamenewage 2004-12-01
  • 打赏
  • 举报
回复
to 楼上
// void *p = &classC2;
// classC1.SetClass( (CClassA*)&p ); // 如果没有上面,这里可能出现问题
classC1.SetClass( (CClassA*)&classC2 ); //没有用那句void *p,确实没有问题 @-@!!
你所改的就是上面三句吗?
我最初的写法就是这样的。你看看在你那边pClass与classC1.m_pClass与pClassTrue这三个值相等吗?

不过我想,你的写法应该是正确的,会不会系统将地址的转变是为了保证“2、ClassA里面能够通过这个指针访问任何派生对象中ClassA中的数据”

难道你真的还是不明白我的意图吗?:( 让我晕倒你要负责。
lifezhu 2004-11-30
  • 打赏
  • 举报
回复
用你的代码,几乎原封不动地照抄,只是没有使用void*,一点问题都没有,不知所云
////////////////////////// class A
class CClassC;
class CClassA
{
int m_dwClassASize;
CClassA *m_pClass;
public:
CClassA(void){}
~CClassA(void){}

void SetClass( CClassA *pClass )
{
m_pClass = pClass;
}
CClassC *GetClass(void)
{
CClassC *pClass;
pClass = (CClassC *)m_pClass; // 这里可能出现问题

return pClass;
}
void DelClass(CClassA *pClass)
{
if( pClass==m_pClass ) // 这里没有相等的情况
m_pClass = 0;
}
};


////////////////////////// class B
class CClassB
{
int m_dwClassBSize;
public:
CClassB(void){}
~CClassB(void){}
};

////////////////////////// class C
class CClassC : public CClassB,public CClassA
{
int iState;
public:
CClassC(void){}
~CClassC(void){}
};


void main(void)
{
CClassC classC1;
CClassC classC2;

// void *p = &classC2;

// classC1.SetClass( (CClassA*)&p ); // 如果没有上面,这里可能出现问题

classC1.SetClass( (CClassA*)&classC2 ); //没有用那句void *p,确实没有问题 @-@!!
CClassC *pClass;
CClassC *pClassTrue = &classC2;

pClass = (CClassC *)classC1.GetClass( );
classC1.DelClass( pClassTrue );
}
lifezhu 2004-11-30
  • 打赏
  • 举报
回复
1.不要乱用void*,那会丢失你所有的类型信息
2.系统结构混乱?ClassA为ClassC的基类,而ClassA又知道ClassC的存在
或者说:
ClassC IsA ClassA,同时,ClassA Holds ClassC,循环依赖
3.从多个类中派生,最好使用RTTI和异常机制,在类型转换时使用dynamic_cast<ClassA*>(p)

强制类型转换可以使用reinterfret_cast<ClassA*>(p),但最好不要使用
healer_kx 2004-11-30
  • 打赏
  • 举报
回复
to : xghost(菜鸟)
这次是对的:)
healer_kx 2004-11-30
  • 打赏
  • 举报
回复
class A
{
public:
virtual void func1();
}; //sizeof(A) = 4, 虚表指针的大小

class B
{
public:
virtual void func2();
}; //同理。

class C : public A, public B //注意,继承是有顺序的,影响了虚表的指针排列顺序。
{
public:
void func1()
{
printf("func1");
}
void func2()
{
printf("func2");
}
};

C* pc = new C;
void* v = pc;

((B*)v)->func2();
注意!!!!!!
调用了A的func1, 就是因为上面我说得, B的虚表没有了, 指向了A的虚表, func2的地址也是指着A::func1()的地方。

要分不是我本意,我说着玩的。我本来在CSDN上倒分的。那是一年前的事情了。那时候还写过道歉的帖子:)
呵呵,大家能共同进步就好。
healer_kx 2004-11-30
  • 打赏
  • 举报
回复
TO: xghost(菜鸟)
这位兄台说得似乎不对啊,要么就是我理解错了。

看代码:
class A
{
virtual void func1();
}; //sizeof(A) = 4, 虚表指针的大小

class B
{
virtual void func2();
}; //同理。

class C : public A, public B //注意,继承是有顺序的,影响了虚表的指针排列顺序。
{
//你必须实现AB接口才能创建实例吧()
}

C* pc = new C;
不要传给void*,
现在C的虚表顺序为A的虚表, B的虚表!
加入你传递给了void*指针, 情况就不一样了! , B的虚表将会被“淹没”,就是不会再体现出来了。
以至于 ,这样的操作(B*)((void*)pc)都不会以多态的方式调用的B的虚函数了。!

所以一定要小心, 在多重继承的时候, 指针的转化向上向下要注意虚表被淹没了。 否则就不能体现出多态了。

像楼主你说的问题, 要把(B*)这种所谓的显示转化理解为指针的操作。

(B*)pc的操作, 实际上是把pc(C类实例的指针)的虚表从C(A)指向了B的虚表的位置。(这里C与A的虚表的指针在一起了)

PS,忘记说了sizeof(C) = 8; 是A和B的虚表指针和。
jiangchun_xn 2004-11-30
  • 打赏
  • 举报
回复
B *s = new B;
printf("%p\n",s);
A *ss = (A *)s;
printf("%p\n",ss);
B *sss = (B *)ss;
printf("%p\n",sss);
}
也没发生变化啊。
jiangchun_xn 2004-11-30
  • 打赏
  • 举报
回复
class A {
public:
int a;
};
class B :public A{
public:
int b;
};
int main(int argc, char* argv[])
{

B *s = new B;
printf("%p\n",s);
A *ss = (A *)s;
printf("%p\n",ss);
return 0;
}

没发生变化啊。

gamenewage 2004-11-30
  • 打赏
  • 举报
回复
to 楼上
你的代码是想实现安全的类型转换,其实在我的类里面也有动态类型转换的机制。是通过在每一个类中定义一个static 的数据,相同的类数据相同,不同的类数据不同,每次使用类型转换的时候,先看static数据与指定类的是否想等,相等就返回this指针。但是如果偏移地址错误,调用this指针就已经错误。
这么说吧!我在ClassA里面只想定义一个变量,这个变量保存指针,我不管这个指针指向什么类类型。我只希望这个指针在保存之前与读取之后是同样的值。可是这个指针变量如果定义成ClassA*,读取的值就会不同,如果定义成void*就没问题。仅仅是个指针,为什么系统在转换的时候非得要变化这个指针地址,这是为了保证什么情况下的安全吗?
简单来说我的意图是这样子:
就是在父对象里面保存一个指针,这个指针指向任何可能的派生类对象(派生类可能会多继承),我要求,1、这个指针在存取前后不会改变;2、甚至在ClassA里面能够通过这个指针访问任何派生对象中ClassA中的数据。
我的意图能实现吗?怎么做呢?
lifezhu 2004-11-30
  • 打赏
  • 举报
回复
纠正一个小错误
template<T>
void DelClass(T *pClass)
{
CClassA* pA;
try {pA=dynamic_cast<CClassA*>(pClass);}catch(...){pA=NULL;}

if( pA==m_pClass )
m_pClass = NULL;
}
lifezhu 2004-11-30
  • 打赏
  • 举报
回复
虽然还是没看懂你想干什么,还是建议
GetClass和DelClass做如下修改
template<T>
T* GetClass(void)
{
T *pClass;

try {pClass=dynamic_cast<T*>(m_pClass);}catch(...){pClass=NULL;}
return pClass;
}
template<T>
void DelClass(T *pClass)
{
CClassA* pA;
try {pA=dynamic_cast<T*>(pClass);}catch(...){pA=NULL;}

if( pA==m_pClass )
m_pClass = NULL;
}
};
gamenewage 2004-11-30
  • 打赏
  • 举报
回复
更正一下,应该是:
……程序里面使用了一系列的ClassC的实例对象(诸如std::list<ClassC>定义的列表),也不排除以后会使用ClassD实例对象的可能……
gamenewage 2004-11-30
  • 打赏
  • 举报
回复
to healer_kx(天降甘草) ,你说得很好,先谢着。

可能上面各位还不完全明白我的意思,我当然并不想在ClassA里面涉及到ClassC的操作。
我的本意是这样的,程序里面使用了一系列的ClassC,也不排除以后会使用ClassD..的可能,程序里面本身考虑了使用类似SafeCast()这类的类类型检查,按理说不应该出现用这个类指针调用其他类实例的可能。ClassA作为基本的一个特性,不会单独使用,但是在这个类型里面的操作要涉及到其他的ClassA派生类对象(可能是ClassD或者ClassE..),我为了不在ClassA里面涉及任何派生类。用ClassA*保存了任何相关联的ClassA派生类实例的地址。(开始我也觉得危险,但是没有什么好的办法来实现ClassA派生类关系的保存)我仅仅只是想保存这个地址,在使用的时候再把它看成相应的对象来使用。可是就在地址保存和读取的时候发生了变化。
所以在这请教各位了。或者是我的做法有什么不妥之处,还望给个建议。
xghost 2004-11-29
  • 打赏
  • 举报
回复
写错了应该是
ptC == ptD + sizeof(B);
ptD == ptB;

xghost 2004-11-29
  • 打赏
  • 举报
回复
To:whoho(在北方流浪)

若使用通常的C++对象模型,这样的继承 class D : B, C

ptD == ptB + sizeof(B)
应该是
ptB == ptC == ptD + sizeof(B)
whoho 2004-11-29
  • 打赏
  • 举报
回复
你先转换为void*,然后作其他动作试试看
gamenewage 2004-11-29
  • 打赏
  • 举报
回复
to whoho(在北方流浪)
我估计也是这样子,可是为什么系统硬是要在强制类型转换的时候要把指针作了偏移,用户并不希望指针这东西发生变化啊。
那么要实现我程序中的意图,又怎样解决这个问题呢?
加载更多回复(15)

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧