Рассмотрим два указателя
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 должен быть расположен перед этим членом, стандарт не предписывает виртуальные таблицы и ничего не говорит о макете класса.
Итак, мои вопросы:
Является ли предлагаемое решение правильным со стандартной точки зрения?
Есть ли какие-либо предостережения о частном (защищенном) наследовании или 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");
}
}