При чтении предмета 27 сверните приведение Эффективный C ++, он говорит, что не пытайтесь использовать static_cast
транслировать *this
в производном классе до базового класса. Это потому что static_cast<Base>(*this)
создаст временный объект базового класса. Я попробовал следующий пример, однако он всегда выдает 10 с использованием разных компиляторов, таких как clang 3.8 и gcc 4.9, 5.3.
Я ошибся?
#include <iostream>
class A {
public:
int a;
virtual void foo() {std::cout << a << std::endl;}
};
class B : public A {
public:
int b;
void foo () { static_cast<A>(*this).foo();}
};int main () {
B b;
b.a = 10;
b.foo();
return 0;
}
Вопрос почему static_cast
создаст временный объект.
Более значимым примером будет этот:
#include <iostream>
class A {
public:
virtual void foo() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
virtual void foo() { std::cout << "B" << std::endl; }
void bar () { static_cast<A>(*this).foo(); }
};
int main () {
B b;
b.bar();
}
Я бы ожидал bar
печатать B
, за foo
это переопределенный метод. Это печатает A
вместо.
Ну, это правильно с точки зрения языка, не так хорошо с точки зрения разработчика, который ожидал совершенно другого результата.
Это работает, если вы используете вместо этого следующий класс:
class B : public A {
public:
virtual void foo() { std::cout << "B" << std::endl; }
void bar () { static_cast<A*>(this)->foo(); }
};
Также следующее работает как ожидалось (добавлено для ясности, благодаря @MORTAL в комментариях):
class B : public A {
public:
virtual void foo() { std::cout << "B" << std::endl; }
void bar () { static_cast<A&>(*this).foo(); }
};
Во всяком случае, проблема, с которой вы сталкиваетесь, называется нарезка.
Вот почему с помощью static_cast<A>(*this)
не рекомендуется, если вы не знаете, что делаете.
Увидеть Вот для дальнейших деталей.
Прежде всего вам не нужно разыгрывать Derived -> Base, потому что это происходит автоматически. И да, static_cast создаст объект типа, к которому вы приводите.
В вашем случае, чтобы включить полиморфизм, вы можете использовать ссылки или указатели:
int main(){
B b;
A &a = b; // no explicit cast needed
a.foo(); // will call B::foo
//OR
B *bPtr = new B;
A *aPtr = bPtr; // no explicit cast needed
aPtr->foo(); // same as above
}