Рассмотрим два указателя
A* a;
B* b;
Оба A и B являются полиморфными классами. Как проверить, указывают ли a и b один и тот же объект?
Точнее, пусть указать a и b указывают на один и тот же объект, если существует некоторый объект d типа D, такой, что оба * a и * b находятся где-то в иерархии классов d.
Я бы предложил следующее решение:
dynamic_cast<void*>(a) == dynamic_cast<void*>(b)
Действительно, согласно стандарту,
dynamic_cast<void*>(v)
дает "указатель на самый производный объект, на который указывает v. (n3242.pdf: § 5.2.7-7). Если наиболее выведенным для обоих является один и тот же объект, то указатели указывают на один и тот же объект.
Я уверен, что он должен всегда правильно работать с практической точки зрения. Но теоретически, на первый взгляд, предлагаемое равенство, по-видимому, создает ложноположительные, например, в случае, если b указывает на первый член A (а не на предка). Хотя практически невозможно получить равные адреса для A и его членов, так как перед этим членом должен быть размещен указатель виртуальной таблицы, стандарт не предоставляет виртуальные таблицы и ничего не говорит о макете класса.
Итак, мои вопросы:
-
Является ли предлагаемое решение правильным со стандартной точки зрения?
-
Есть ли какие-либо предостережения о частном (защищенном) наследовании или cv-квалификации?
-
Есть ли лучшие решения?
[EDIT]
Я попытался привести пример, иллюстрирующий относительно сложный сценарий. В этом случае динамическое кросс-кастинг и статическое литье неоднозначны.
// 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");
}
}