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
}
Другие вопросы по тегам