static_cast вывел этот объект в базовый класс в C++
При чтении пункта 27 "Минимизируйте приведение типов в Effective 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
создаст временный объект.
3 ответа
Более значимым примером будет этот:
#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)
не рекомендуется, если вы не знаете, что делаете.
Смотрите здесь для более подробной информации.
Проблема с вашим кодом в том, что вы не изменяете значение 's
a
переменная, поэтому вы не видите изменения между значениями двух экземпляров.
Добавьте следующий конструктор копирования для
A
:
A() = default; // so that it still exists...
A(A const& other)
: a(other.a + 1) // initialise to a value definitely differing...
{ }
Теперь вместо этого вы должны увидеть 11, что подтверждает утверждение...
Прежде всего вам не нужно разыгрывать 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
}