不传参,不模板:父类获取子类指针?

Loaden 2009-11-05 01:09:20
这个问题我想了一天了,也没解决。
注意:不传参数,也不用模板。

13:35:28 更新:不好意思,忘了说,还需要两个条件:
① 只能在构造函数里转换。
② 设计上必须让A成为基类,B不能成为基类。


请指点。

#include <iostream>

using namespace std;

class A
{
public:
A() { cout << "A: " << this << endl; }
virtual ~A() {}
virtual void say() { cout << "A!" << endl; }

protected:
int i;
};

A* g_p = 0;

class D
{
public:
D() { cout << "D: " << this << endl; }
virtual ~D() {}
virtual void say() { cout << "D!" << endl; }

protected:
char c;
};

class B : public D
{
public:
B() { g_p = reinterpret_cast<A*>(this); cout << "B: " << this << endl; }
virtual ~B() {}
virtual void say() { cout << "B!" << endl; }

protected:
int i;
char c[100];
};

class C : public A, public B
{
public:
C() { cout << "C: " << this << endl; }
virtual ~C() {}
virtual void say() { cout << "C!" << endl; }

protected:
float f;
int i;
char c[256];
};

int main()
{
C c;
cout << "问题是:g_p != &c : " << g_p << " != " << &c << endl;
if (g_p != NULL) g_p->say();
return 0;
}

运行结果:
A: 0012FDD8
D: 0012FDE0
B: 0012FDE0
C: 0012FDD8
问题是:g_p != &c : 0012FDE0 != 0012FDD8
C!


虽然可以输出C!,但地址不一样。
我的问题:如何让g_p的地址与&c一样呢?
...全文
1046 109 打赏 收藏 转发到动态 举报
写回复
用AI写文章
109 条回复
切换为时间正序
请发表友善的回复…
发表回复
xf_pan 2011-01-07
  • 打赏
  • 举报
回复
好帖,,101
「已注销」 2009-11-10
  • 打赏
  • 举报
回复
顶一下!
「已注销」 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 93 楼 yutaooo 的回复:]
楼主。放弃这个疯狂的方案吧。如果,只是为了自己演练,熟悉语言特性,那无可厚非。但千万不要用在产品上,更不能传播这样的想法。因为,它不是个好主意,最终会招来不快的体验,难以更进一步。

本意是解耦合,希望在类之间,头文件之间摆脱依赖关系。然而,事实上是引入了最恐怖的语意依赖。为了将这样的依赖关系在将来的代码维护中维持下去,需要更多的文档去描述。这真是个非常规的设计,仅仅从代码中,很难推敲出逻辑的关系。

类和对象,应该有关系的地方,就要强力体现。降低耦合不是杜绝耦合,何况根本无法杜绝更引入了概念上有关系而实现上没有关系。
[/Quote]
有的代码只能走非常规设计。
常规的是低效,非常规的才高效。
比如Thunk!
我的界面库完全基于Thunk!
等有空了,我会实现内存池,来统一管理thunk代码。
fblgzdq 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 93 楼 yutaooo 的回复:]
楼主。放弃这个疯狂的方案吧。如果,只是为了自己演练,熟悉语言特性,那无可厚非。但千万不要用在产品上,更不能传播这样的想法。因为,它不是个好主意,最终会招来不快的体验,难以更进一步。

本意是解耦合,希望在类之间,头文件之间摆脱依赖关系。然而,事实上是引入了最恐怖的语意依赖。为了将这样的依赖关系在将来的代码维护中维持下去,需要更多的文档去描述。这真是个非常规的设计,仅仅从代码中,很难推敲出逻辑的关系。

类和对象,应该有关系的地方,就要强力体现。降低耦合不是杜绝耦合,何况根本无法杜绝更引入了概念上有关系而实现上没有关系。
[/Quote]


d
underuwing 2009-11-08
  • 打赏
  • 举报
回复
我有个地方没看明白,为什么父类和子类的地址是一样的呢?
「已注销」 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 106 楼 mengde007 的回复:]
引用 105 楼 hikaliv 的回复:
…………………………………………

再随个礼……

传说中的王者归来!
[/Quote]
牛人!
mengde007 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 105 楼 hikaliv 的回复:]
…………………………………………

再随个礼……
[/Quote]
传说中的王者归来!
光宇广贞 2009-11-08
  • 打赏
  • 举报
回复
…………………………………………

再随个礼……
drysea 2009-11-08
  • 打赏
  • 举报
回复
解决了????????

恭喜恭喜……随个礼吧。
drysea 2009-11-08
  • 打赏
  • 举报
回复
解决了????????

恭喜恭喜……随个礼吧。
mengde007 2009-11-08
  • 打赏
  • 举报
回复
呵呵;占了第二页的1楼
mengde007 2009-11-08
  • 打赏
  • 举报
回复
COM里面也讲过一些通过固定偏移来求得指针地址的方法;
「已注销」 2009-11-08
  • 打赏
  • 举报
回复
突然发现可以抢100,抢:100
「已注销」 2009-11-08
  • 打赏
  • 举报
回复
突然发现可以抢100,抢:99
「已注销」 2009-11-08
  • 打赏
  • 举报
回复
[Quote=引用 97 楼 deng2000 的回复:]
纯属好玩,再用一种比较粗暴的方法实现楼主的要求: 在B的附件寻找A的虚表指针以得到A的位置.
...
这种方法比起用嵌套类对C的限制条件更宽松些: 除了A与B,C也还可以同时继承其它类,只要保证在继承的序列中,A出现在B的前面(A与B不一定要相邻,如上面程序所示).当然,它也增加了很多条件,例如A要有虚函数,A没有自定义拷贝构造函数等.

再次声明:此方法只是用于探讨楼主的问题, 并不意味着它可用于实际工作中 .
[/Quote]
太厉害了!
GCC 4.4.1也通过!
学习中...
谢谢!
deng2000 2009-11-08
  • 打赏
  • 举报
回复
纯属好玩,再用一种比较粗暴的方法实现楼主的要求: 在B的附件寻找A的虚表指针以得到A的位置.程序如下:


#include <iostream>

using namespace std;

class A
{
public:
A() {
cout << "A: " << this << endl;
}
virtual ~A() {}
virtual void say() { cout << "A!" << endl; }

protected:
int i;
};

A* g_p = 0;

class D
{
public:
D() { cout << "D: " << this << endl; }
virtual ~D() {}
virtual void say() { cout << "D!" << endl; }

protected:
char c;
};

class C;

class B : public D
{
public:
B() {
static int nOffset = 0;
if (nOffset == 0) {
class DerivedA : public A {
// helper class to find the position of vptr in A
public:
virtual ~DerivedA() {};
};
A a;
DerivedA da;
a = da;
// now, between the layout of da and a, only vptr is different

int nSizeA = sizeof(A);

// Calculate the position of vptr in A
int nVptrOffset;
int nVptrValue;
for (int i=0; i<nSizeA/4; i++) {
int *pr1 = (int *)&a + i;
int *pr2 = (int *)&da + i;
if (*pr1 != *pr2) {
nVptrOffset = i*4;
nVptrValue = *pr1;
break;
}
}

// scan in the neighbour for the vptr of A
int *pFirst = (int *)this;
int *pSecond = (int *)((char *)this + sizeof(B));
for (int i=0; i<100; i++) {
if (*pFirst == nVptrValue) {
nOffset = ((char *)pFirst - (char *)this);
break;
}
else if (*pSecond == nVptrValue) {
nOffset = ((char *)pSecond - (char *)this);
break;
}

pFirst --;
pSecond ++;
}

if (nOffset != 0)
nOffset -= nVptrOffset;
}

if (nOffset != 0) {
g_p = (A*)((char *)this + nOffset);
}
else {
g_p = NULL;
}

};
virtual ~B() {}
virtual void say() { cout << "B!" << endl; }

protected:
int i;
char c[100];
};

class Tmp
{
int m[5];
};

class C : public A,public Tmp, public B
{
public:
C() { cout << "C: " << this << endl; }
virtual ~C() {}
virtual void say() { cout << "C!" << endl; }

protected:
float f;
int i;
char c[256];
};


int main()
{
C c;
cout << "Problem: g_p != &c : " << g_p << " != " << &c << endl;
if (g_p != NULL) g_p->say();
return 0;
}





这种方法比起用嵌套类对C的限制条件更宽松些: 除了A与B,C也还可以同时继承其它类,只要保证在继承的序列中,A出现在B的前面(A与B不一定要相邻,如上面程序所示).当然,它也增加了很多条件,例如A要有虚函数,A没有自定义拷贝构造函数等.

再次声明:此方法只是用于探讨楼主的问题, 并不意味着它可用于实际工作中 .
bawgiitx 2009-11-07
  • 打赏
  • 举报
回复
又学到一招了,3Q
SammyLan 2009-11-07
  • 打赏
  • 举报
回复
只是
这跟已经知道C的定义有什么区别?
SammyLan 2009-11-07
  • 打赏
  • 举报
回复
[Quote=引用 83 楼 deng2000 的回复:]
引用 72 楼 loaden 的回复:
有没有不在B构造函数之前包含C类定义,就可以得到C的this指针的方法呢?
注意:还得满足0楼的要求。

先加到150分,请继续讨论!
再次感谢!


此要求稍显无理,呵呵
在定义B构造函数时,我们可以不用知道C的定义,但我们需要预先知道一点:C只按顺序从A和B继承(否则的话,设另有一个类E,C从A,E,B多重继承,编译量就完全变了,怎么也不可能在B的构造函数中得出此偏移量)。
在确认C是按顺序从A和B继承的前提下,我们可以在B的构造函数中定义一个嵌套类来模拟C的布局,从而达到你的新要求。程序如下:
C/C++ code

#include<iostream>usingnamespace std;class A
{public:
A() { cout<<"A:"<<this<< endl; }virtual~A() {}virtualvoid say() { cout<<"A!"<< endl; }protected:int i;
};

A* g_p=0;class D
{public:
D() { cout<<"D:"<<this<< endl; }virtual~D() {}virtualvoid say() { cout<<"D!"<< endl; }protected:char c;
};class C;class B :public D
{public:
B() {class C2 :public A,public B
{// a embeded class to mimic the layout of Cint n;
};

C2* pC= (C2*)4096;// Any value except NULL is ok. We don't care whatever pC points to B* pB= pC;int n= (char*)pC- (char*)pB;
g_p= (A*)((char*)this+ n);
cout<<"B:"<<this<< endl;
};virtual~B() {}virtualvoid say() { cout<<"B!"<< endl; }protected:int i;char c[100];
};class C :public A,public B
{public:
C() { cout<<"C:"<<this<< endl; }virtual~C() {}virtualvoid say() { cout<<"C!"<< endl; }protected:float f;int i;char c[256];
};int main()
{
C c;
cout<<"Problem: g_p != &c :"<< g_p<<" !="<<&c<< endl;if (g_p!= NULL) g_p->say();return0;
}
[/Quote]

你这里搞那么复杂干嘛?


直接这样不就得了

B() {
class Proxy:public A,public B
{

};
Proxy * p =(Proxy*)this;

g_p = (A*)p;
cout << "B: " << this << endl;
}
「已注销」 2009-11-07
  • 打赏
  • 举报
回复
不过,我并没有将实现放在另一个CPP里。
上面的代码都放在一个源文件中。

我不认为放在另一个CPP中就会得到正确结果。
因为两种实现是一样的。
编译器不应该因为我将代码放在不同的位置,而生成不同的指令。
SammyLan能否帮忙跑一下51楼的代码。
加载更多回复(89)

65,206

社区成员

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

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