Как заменить указатели ссылками на С++?

"Я уверен, что есть десятки вопросов с одним и тем же названием. Многие из них дублируются. Моя может быть дублирована, но я не мог ее найти. Поэтому я стараюсь сделать ее очень аккуратной, короткой и простой."

У меня есть такая иерархия:

class Shape {
public:
   virtual void virtualfunc()  { std::cout << "In shape\n"; }
};

class Circle: public Shape {
public:
   void virtualfunc()  { std::cout << "In Circle\n"; };
};

и когда я использую классы с помощью указателя, функции вызываются так, как я ожидал:

int main() {
   Shape shape_instance;
   Shape* ref_shape = &shape_instance ;
   Circle circle_instance;
   Circle* ref_circle = &circle_instance;

   ref_shape = dynamic_cast<Shape*> (ref_circle);
   ref_shape->virtualfunc();
}

Здесь программа вызывает virtualfunc() производного класса, и результат естественно: In Circle

Теперь я хочу избавиться от указателей, вместо этого использовать ссылки и получить тот же результат. Поэтому я делаю тривиальные изменения в main(), чтобы выглядеть так:

int main() {
   Shape shape_instance;
   Shape& ref_shape = shape_instance;
   Circle circle_instance;
   Circle& ref_circle = circle_instance;

   ref_shape = dynamic_cast<Shape&>(ref_circle);
   ref_shape.virtualfunc();
}

Но на этот раз программа вызывает virtualfunc() базового класса, а результат: In Shape

Я ценю, если вы сообщите мне, какую концепцию ссылок мне не хватает, и как изменить ссылки в main(), чтобы получить результат, который я получил в версии указателя.

Благодарю вас

Ответы

Ответ 1

Ссылки не могут быть пересмотрены. Когда вы инициализируете ссылку в инициализации, она становится псевдонимом упомянутого объекта и не может отличаться от нее. Последнее назначение:

ref_shape = dynamic_cast<Shape&>(ref_circle);

действительно означает:

shape_instance = dynamic_cast<Shape&>(ref_circle);

С другой стороны, вы можете привязать новую ссылку к объекту (и вам не нужен dynamic_cast, так как преобразование из ссылки на производную на ссылку на базу неявно):

Shape & another_ref = ref_circle;
another_ref.virtualfunc();          // Dispatches to Circle::virtualfunc

Ответ 2

Здесь ваш Circle превращается в Shape.

ref_shape = dynamic_cast<Shape&>(ref_circle);
//        ^ here
ref_shape.virtualfunc();

ref_shape уже определен как ссылка на shape_instance.

Вы не копируете саму ссылку, так как ссылки не могут быть переназначены. Вы копируете фактический объект в объект Shape. Он сохраняется в shape_instance.

Вы можете проверить это, попробовав этот код. Он напечатает In Circle.

dynamic_cast<Shape&>(ref_circle).virtualfunc();

Ответ 3

Вы должны сделать следующее:

#include <iostream>

 class Shape {
  public:
   virtual void virtualfunc()  { std::cout << "In shape\n"; }
 };

 class Circle: public Shape {
   public:
   void virtualfunc()  { std::cout << "In Circle\n"; };
 };

 int main() {
    Shape shape_instance;
    //Shape& ref_shape = shape_instance;
    Circle circle_instance;
    Circle& ref_circle = circle_instance;

    Shape& ref_shape = dynamic_cast<Shape&>(ref_circle);
    ref_shape.virtualfunc();
}

Он выводится в круге, как вы ожидали.

Ответ 4

Если я правильно понимаю, что вы пытаетесь достичь/показать (т.е. привязка к динамической виртуальной функции), возможно, этот код поможет:

#include <iostream>
using namespace std;

class Shape {
  public:
    virtual void virtualfunc()  { std::cout << "In shape\n"; }
};

class Circle: public Shape {
  public:
    void virtualfunc()  { std::cout << "In Circle\n"; };
};

int main() {
  Circle circle_instance;

  // don't care what kind of Shape
  Shape &someShape = circle_instance;

  someShape.virtualfunc();
}

Здесь вы можете видеть, что someShape может быть привязано к Shape или любому производному классу, и виртуальная функция будет вызываться в текущем динамическом типе . Это напечатает In Circle. Доказательство: http://ideone.com/A1UvrR

Нет необходимости в dynamic_cast