Но давайте скажем, что мне нужна функция, которая возвращает значение Animal, которое действительно является Dog.
- Правильно ли я понимаю, что самое близкое, что я могу получить, - это ссылка?
Да, вы правы. Но я думаю, что проблема не в том, что вы не понимаете ссылки, а в том, что вы не понимаете различные типы переменных в C ++ или как new
работает в C ++. В C ++ переменные могут быть примитивными данными (int, float, double и т. Д.), Объектом или указателем / ссылкой на примитив и / или объект. В Java переменные могут быть только примитивами или ссылками на объект.
В C ++, когда вы объявляете переменную, фактическая память выделяется и связывается с переменной. В Java вы должны явно создавать объекты, используя new, и явно назначать новый объект переменной. Ключевым моментом здесь является то, что в C ++ объект и переменная, которую вы используете для доступа, не одно и то же, когда переменная является указателем или ссылкой. Animal a;
означает что-то отличное от Animal *a;
, что означает что-то отличное от Animal &a;
. Ни у одного из них нет совместимых типов, и они не являются взаимозаменяемыми.
Когда вы печатаете, Animal a1
в C ++. Новый объект Animal
создан. Таким образом, когда вы набираете Animal a2 = a1;
, вы получаете две переменные (a1
и a2
) и два Animal
объекта в разных местах памяти. Оба объекта имеют одинаковое значение, но вы можете изменить их значения независимо, если хотите. В Java, если вы ввели один и тот же точный код, вы бы получили две переменные, но только один объект. Если вы не переназначили ни одну из переменных, они всегда будут иметь одно и то же значение.
- Кроме того, обязан ли тот, кто использует интерфейс rFunc, видеть, что возвращаемая ссылка назначена Animal &? (Или иным образом намеренно назначьте ссылку на Животное, которое посредством нарезки отбрасывает полиморфизм.)
Когда вы используете ссылки и указатели, вы можете получить доступ к значению объекта, не копируя его туда, где вы хотите его использовать. Это позволяет вам изменить его вне фигурных скобок, где вы объявили объект в существование. Ссылки обычно используются в качестве параметров функции или для возврата закрытых членов данных объекта без создания их новой копии. Как правило, когда вы получаете ссылку, вы ничего не назначаете. Используя ваш пример, вместо присвоения переменной, возвращаемой rFunc()
, переменной, обычно введите rFunc().makeSound();
.
Так что, да, пользователь rFunc()
обязан, если он присваивает возвращаемое значение чему-либо, назначить его для ссылки. Вы можете понять почему. Если вы назначите ссылку, возвращаемую rFunc()
, переменной, объявленной как Animal animal_variable
, вы получите одну Animal
переменную, один Animal
объект и один Dog
объект. Объект Animal
, связанный с animal_variable
, является, насколько это возможно, копией объекта Dog
, который был возвращен по ссылке из rFunc()
. Но вы не можете получить полиморфное поведение от animal_variable
, потому что эта переменная не связана с Dog
объектом. Объект Dog
, который был возвращен по ссылке, все еще существует, потому что вы создали его с помощью new
, но он больше недоступен - утечка произошла.
- Как же я должен возвращать ссылку на вновь сгенерированный объект, не делая глупостей, которые я делал выше в rFunc? (По крайней мере, я слышал, что это глупо.)
Проблема в том, что вы можете создать объект тремя способами.
{ // the following expressions evaluate to ...
Animal local;
// an object that will be destroyed when control exits this block
Animal();
// an unamed object that will be destroyed immediately if not bound to a reference
new Animal();
// an unamed Animal *pointer* that can't be deleted unless it is assigned to a Animal pointer variable.
{
// doing other stuff
}
} // <- local destroyed
Все, что new
делает в C ++, это создает объекты в памяти, где они не будут уничтожены, пока вы не скажете это. Но чтобы уничтожить его, вы должны помнить, где он был создан в памяти. Вы делаете это путем создания переменной указателя,
Animal *AnimalPointer;
,
и присвоение указателя, возвращенного new Animal()
,
AnimalPointer = new Animal();
.
Чтобы уничтожить объект Animal
, когда вы закончите с ним, вы должны набрать delete AnimalPointer;
.