#c #inheritance #pointers #dynamic-cast
#c #наследование #указатели #динамическое приведение
Вопрос:
Я хотел бы получить некоторую информацию о лучших практиках при сравнении указателей в случаях, подобных этому:
class Base {
};
class Derived
: public Base {
};
Derived* d = new Derived;
Base* b = dynamic_cast<Base*>(d);
// When comparing the two pointers should I cast them
// to the same type or does it not even matter?
bool theSame = b == d;
// Or, bool theSame = dynamic_cast<Derived*>(b) == d?
Ответ №1:
Если вы хотите сравнить произвольные иерархии классов, безопаснее всего сделать их полиморфными и использовать dynamic_cast
class Base {
virtual ~Base() { }
};
class Derived
: public Base {
};
Derived* d = new Derived;
Base* b = dynamic_cast<Base*>(d);
// When comparing the two pointers should I cast them
// to the same type or does it not even matter?
bool theSame = dynamic_cast<void*>(b) == dynamic_cast<void*>(d);
Учтите, что иногда вы не можете использовать static_cast или неявное преобразование из производного в базовый класс:
struct A { };
struct B : A { };
struct C : A { };
struct D : B, C { };
A * a = ...;
D * d = ...;
/* static casting A to D would fail, because there are multiple A's for one D */
/* dynamic_cast<void*>(a) magically converts your a to the D pointer, no matter
* what of the two A it points to.
*/
Если A
наследуется виртуально, вы также не можете выполнять static_cast в D
.
Комментарии:
1. Другим безопасным вариантом было бы использовать
static_cast
для преобразования их обоих в общую базу. При условии, конечно, что вы знаете общую базу. В противном случае: если один указатель является базовым типом другого, компилятор выполнит преобразование автоматически.
Ответ №2:
В приведенном выше случае вам не требуется никакого приведения, сработает простое Base* b = d;
. Затем вы можете сравнить указатели, как вы сравниваете сейчас.