Как заменить указатели ссылками на С++?
"Я уверен, что есть десятки вопросов с одним и тем же названием. Многие из них дублируются. Моя может быть дублирована, но я не мог ее найти. Поэтому я стараюсь сделать ее очень аккуратной, короткой и простой."
У меня есть такая иерархия:
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