2012-04-02 56 views
13

考虑两个指针如何检查两个指针​​是否指向同一个对象?

A* a; 
B* b; 

A和B是多态的类。 如何检查a和b是否指向同一个对象?

更准确地说,我们指定a和b指向同一个对象,如果存在类型d的一些对象d,使得两个*和* b是d的类层次结构的某个地方。

我建议如下解决方案:

dynamic_cast<void*>(a) == dynamic_cast<void*>(b) 

实际上,根据该标准,

dynamic_cast<void*>(v) 

产量“的指针最派生对象用V指向(n3242.pdf。 :§5.2.7 - 7)。 如果两者的派生最相同的对象,那么指针指向同一个对象。

我很确定它应该始终从实际的角度正确工作。但理论上,乍看之下,所提出的平等似乎会产生误判,例如,如果b指向A的第一个成员(而不是A的祖先)。虽然A和它的成员实际上不可能获得相同的地址,因为A的虚拟表指针应该位于该成员之前,但该标准并没有强制虚拟表并且没有提及类布局。

所以,我的问题是:

  1. 是所提出的解决方案,从标准的角度看是否正确?

  2. 有没有关于私人(受保护)继承或cv资格的警告?

  3. 有没有更好的解决方案?

[编辑]

我试图提出一些例子示出了相对复杂的场景。在这种情况下,动态交叉转换和静态转换是不明确的。

// 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"); 
    } 
} 
+11

为什么不'a == b'? – iammilind 2012-04-02 10:24:00

+1

@iammilind:A和B可能是一些D的基类,但彼此无关 – user396672 2012-04-02 10:27:02

+2

@iammilind的+1 - 旧的'uns是最好的! – 2012-04-02 10:27:15

回答

1

我试图通过比较这些指针指向的地址来解决这个问题。

  • 地址它指向基于指针类型的更改。

因此理论上可以说像

a *和b *指向同一个对象,如果存在一些对象C类型C的,使得两个* a和* b是在类某处C.层次结构“

按道理

我们不得不重新审视上述声明像 ” a *和b *指向同一个对象但它obj的ç的内存访问自己的区域C型,使得两个* a和* b是某处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; 

输出:

  • &Ç0x0012fd04
  • &(* A1)0x0012fd04
  • &(* A2)0x0012fd04
  • &(* B1)0x0012fd08
  • &(* b2)的0x0012fd08

虽然这不能解决您的问题,但我们有一点要在此推断。

1

这似乎对我来说是最臭的方式来处理,这是引入一个基类对于A & B:

#include <iostream> 

struct Base 
{ 
    virtual ~Base() {}; 
}; 

struct A : public virtual Base 
{ 
    int a; 
    virtual ~A() {}; 
    virtual void afunc() {}; 
}; 



struct B : public virtual Base 
{ 
    int b; 
    virtual ~B() {}; 
    virtual void bfunc() {}; 
}; 

struct C: A, B 
{}; 

int main() 
{ 
    C c; 
    A *a = &c; 
    B *b = &c; 

    std::cout << "a* == " << &(*a) << std::endl; 
    std::cout << "b* == " << &(*b) << std::endl; 
    std::cout << "a == b == " << ((void*)a == (void*)b) << std::endl; 

    Base* ba = a; 
    Base* bb = b; 

    std::cout << "ba* == " << &(*ba) << std::endl; 
    std::cout << "bb* == " << &(*bb) << std::endl; 
    std::cout << "ba == bb == " << (ba == bb) << std::endl; 

    return 0; 
} 
+0

我同意它是最不臭的,虽然,严格来说,它不是一个答案:)。 – user396672 2012-04-02 17:25:53

0

由于与dynamic_cast您还可以在类型层次投“杯酒人生”,我建议:

(b != nullptr? dynamic_cast<B*>(a) == b : a == nullptr) 

如果a点,在*b开始一些子对象,然后dynamic_cast<B*>(a)必然会返回一个空指针(因为有没有办法B包含自身)。因此,如果b不是空指针,则dynamic_cast<B*>(a) == b只有在共享相同的大多数派生类时才会成功。 b是一个空指针的情况下,必须特别处理,因为如果a不为空,但没有指向从B派生的类,则dynamic_cast测试将失败。

但也有涉及多重继承哪里该解决方案将提供一个假阴性(不像你的解决方案,它从来没有给假阴性,但可产生假阳性)的一些情况。然而,这可能发生的类层次结构是层次结构,我说你不应该创建(即包含多个类型B的间接基地的派生类)。您可以通过交换角色ab再次测试来减少漏报次数(然后仅当均为AB在最派生的类中不明确时,测试将失败)。

您还可以结合你的和我的测试给出三种结果:

  • 这两项测试成功:指针肯定是同一对象(或诺斯空)。
  • 两个测试都失败:指针绝对不是同一个对象。
  • 只有我的测试失败:要么您的测试给出了假阳性,我的测试给出了一个假阴性。你不能确定两者是否是同一个对象,但至少你可以告诉你说不出来。
相关问题