考虑两个指针
A* a;
B* b;
Run Code Online (Sandbox Code Playgroud)
A和B都是多态类.如何检查a和b是否指向同一个对象?
更确切地说,如果存在类型D的某个对象d,则指定a和b指向同一对象,使得*a和*b都在d的类层次结构中的某处.
我建议以下解决方案:
dynamic_cast<void*>(a) == dynamic_cast<void*>(b)
Run Code Online (Sandbox Code Playgroud)
的确,根据标准,
dynamic_cast<void*>(v)
Run Code Online (Sandbox Code Playgroud)
产生"指向v.指向的最派生对象的指针(n3242.pdf:§5.2.7 - 7).如果两者的派生最多是同一个对象,则指针指向同一个对象.
从实际角度来看,我很确定它应该始终正常工作.但理论上,乍一看提议的平等似乎会产生假阳性,例如,如果b指向A的第一个成员(不是A的祖先).虽然实际上不可能为A及其成员获取相同的地址,因为A的虚拟表指针应位于此成员之前,因此该标准不强制要求虚拟表,也不对类布局说明任何内容.
所以,我的问题是:
从标准角度来看,建议的解决方案是否正确?
有关私人(受保护)继承或cv资格的任何警告吗?
有更好的解决方案吗?
[编辑]
我试图提供一些例子来说明一个相对复杂的场景.在这种情况下,动态横向铸造和静态铸造是模糊的.
// proposed impplementation:
template<typename P, typename Q>
bool test_ptrs(const P* p, const Q* q)
{
return (dynamic_cast<const void*>(p) == dynamic_cast<const void*>(q));
}
struct Root
{
virtual ~Root(){};
};
struct A: public Root // nonvirtually
{
};
struct B: public Root // nonvirtually
{
};
struct C: public A, B // nonvirtual diamond started with Root
{
Root another_root_instance;
};
int main()
{
C c;
A* pa= &c;
B* pb= &c;
bool b = (dynamic_cast<void*>(pa) == dynamic_cast<void*>(pb));
Root* pra= dynamic_cast<Root*> (pa);
Root* prb= dynamic_cast<Root*> (pb);
//Root* prc= dynamic_cast<Root*> (&c); // runtime error, ambiguous cast
Root* prr= dynamic_cast<Root*>(pra);
Root* pcar= dynamic_cast<Root*>(pra);
Root* pcbr= dynamic_cast<Root*>(prb);
if(
test_ptrs(pa, pb)
&& test_ptrs(pra, prb)
&& !test_ptrs(pa,&c.another_root_instance)
)
{
printf("\n test passed \n");
}
}
Run Code Online (Sandbox Code Playgroud)
我试图通过比较这些指针指向的地址来解决这个问题。
因此理论上我们可以说
如果存在某个类型为 C 的对象 c,并且 *a 和 *b 都位于 C 的类层次结构中的某个位置,则 a* 和 b* 指向同一个对象。”
逻辑上
我们必须重新审视上面的语句,例如“a * 和 b * 指向同一个对象,但在类型 C 的 obj c 的内存中拥有自己的访问区域,因此 *a 和 *b 都位于 C 类层次结构中的某个位置C。””
struct Aa
{ int a;
Aa() {a= 0;}
};
struct Bb
{ int b;
Bb() { b= 0;}
};
struct C: Aa, Bb {
};
C c;
Aa *a1 = &c;
Aa *a2 = &c;
Bb *b1 = &c;
Bb *b2 = &c;
cout << &c << "\t"<< &(*a1)<<"\t"<< &(*a2)<<endl;
cout << &c << "\t"<< &(*b1)<<"\t"<< &(*b2)<<endl;
Run Code Online (Sandbox Code Playgroud)
输出:
虽然这不能解决您的问题,但我们在这里可以推断出一点。