Consider two pointers
A* a;
B* b;
Both A and B are polymorphic classes. How to check whether a and b point to the same object or not?
More precisely, let's specify a and b point to the same object if there exists some object d of type D such that both *a and *b are somewhere in the class hierarchy of d.
I would propose the following solution:
dynamic_cast<void*>(a) == dynamic_cast<void*>(b)
Indeed, according to the standard,
dynamic_cast<void*>(v)
yields ”a pointer to the most derived object pointed to by v. (n3242.pdf: § 5.2.7 - 7). If the most derived for both is the same object, then the pointers point to the same object.
I'm pretty sure that it should always work correctly from the practical viewpoint. But theoretically, at first glance the proposed equality seems to produce false positive, for example, in case if b points to the first member of A (not to A's ancestor). Although it's practically impossible to get equal addresses for A and its member since A's virtual table pointer should be located before this member, the standard doesn't mandate virtual tables and says nothing about the class layout.
So, my questions are:
Is the proposed solution correct from the standard viewpoint?
Are there any caveats about private (protected) inheritance or cv-qualification ?
Are there better solutions?
[EDIT]
I tried to present some example that illustrates a relatively complex scenario. In this case dynamic crosscasting and static casting are ambiguous.
// 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");
}
}
How to compare pointers in C/C++? We can compare pointers if they are pointing to the same array. Relational pointers can be used to compare two pointers. Pointers can't be multiplied or divided.
In C language pointers can be compared if the two pointers are pointing to the same array. All relational operators can be used for pointer comparison, but a pointer cannot Multiplied or Divided.
When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal.
It would seem to me the least smelly way to deal with this is to introduce a base class for 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With