Я новичок в программировании на C ++, но у меня есть опыт работы с Java. Мне нужно руководство о том, как передавать объекты в функции в C ++.
Нужно ли передавать указатели, ссылки или не указатели и не ссылки? Я помню, в Java нет таких проблем, поскольку мы передаем только переменную, которая содержит ссылку на объекты.
Было бы здорово, если бы вы могли также объяснить, где использовать каждый из этих вариантов.
Ответы:
Практические правила для C ++ 11:
Передать по значению , кроме случаев, когда
const
ссылке ,const
ссылке без значения ,const
ссылке или нет.)Передача по указателю практически никогда не рекомендуется. Необязательные параметры лучше всего выражать как
std::optional
(boost::optional
для старых стандартных библиотек), а псевдонимы выполняются в порядке ссылки.Семантика перемещения в C ++ 11 делает передачу и возврат по значению гораздо привлекательнее даже для сложных объектов.
Практические правила для C ++ 03:
Передавать аргументы по
const
ссылке , кроме случаев, когдаconst
ссылкеNULL
//0
/nullptr
; примените предыдущее правило, чтобы определить, следует ли передавать указатель наconst
аргумент(здесь «передача по значению» называется «передача по копии», потому что передача по значению всегда создает копию в C ++ 03)
Есть еще кое-что, но правила этих нескольких начинающих помогут вам довольно далеко.
источник
Существуют некоторые различия в соглашениях о вызовах в C ++ и Java. В C ++ с технической точки зрения существуют только два соглашения: передача по значению и передача по ссылке, причем некоторые литературные источники включают в себя третье соглашение о передаче по указателю (которое фактически является передачей по значению типа указателя). Кроме того, вы можете добавить константу к типу аргумента, улучшив семантику.
Передать по ссылке
Передача по ссылке означает, что функция концептуально получит экземпляр вашего объекта, а не его копию. Ссылка концептуально является псевдонимом объекта, который использовался в вызывающем контексте, и не может быть нулевым. Все операции, выполняемые внутри функции, применяются к объекту вне функции. Это соглашение не доступно в Java или C.
Передать по значению (и передать по указателю)
Компилятор сгенерирует копию объекта в вызывающем контексте и использует эту копию внутри функции. Все операции, выполняемые внутри функции, выполняются для копии, а не для внешнего элемента. Это соглашение для примитивных типов в Java.
Специальная версия этого передает указатель (адрес объекта) в функцию. Функция получает указатель, и любые и все операции, примененные к самому указателю, применяются к копии (указателю), с другой стороны, операции, примененные к разыменованному указателю, будут применяться к экземпляру объекта в этом месте памяти, поэтому функция может иметь побочные эффекты. Эффект использования передачи по значению указателя на объект позволит внутренней функции изменять внешние значения, как при передаче по ссылке, а также позволит использовать необязательные значения (передать нулевой указатель).
Это соглашение, используемое в C, когда функции необходимо изменить внешнюю переменную, и соглашение, используемое в Java со ссылочными типами: ссылка копируется, но упомянутый объект остается тем же: изменения в ссылке / указателе не видны снаружи функция, но изменения в указанной памяти.
Добавление const к уравнению
В C ++ вы можете присваивать объектам постоянство при определении переменных, указателей и ссылок на разных уровнях. Вы можете объявить переменную постоянной, вы можете объявить ссылку на постоянный экземпляр, и вы можете определить все указатели на постоянные объекты, постоянные указатели на изменяемые объекты и постоянные указатели на постоянные элементы. И наоборот, в Java вы можете определить только один уровень константы (конечное ключевое слово): уровень переменной (экземпляр для примитивных типов, ссылка для ссылочных типов), но вы не можете определить ссылку на неизменный элемент (если только сам класс не является неизменный).
Это широко используется в соглашениях о вызовах C ++. Когда объекты маленькие, вы можете передать объект по значению. Компилятор сгенерирует копию, но эта копия не дорогая операция. Для любого другого типа, если функция не изменит объект, вы можете передать ссылку на постоянный экземпляр (обычно называемый постоянной ссылкой) типа. Это не скопирует объект, но передаст его в функцию. Но в то же время компилятор гарантирует, что объект не будет изменен внутри функции.
Эмпирические правила
Вот некоторые основные правила, которым нужно следовать:
Существуют и другие небольшие отклонения от этих правил, первое из которых касается владения объектом. Когда объект динамически размещается с новым, он должен быть освобожден с удалением (или его версиями []). Объект или функция, которая отвечает за уничтожение объекта, считается владельцем ресурса. Когда динамически размещенный объект создается в фрагменте кода, но право собственности передается другому элементу, это обычно делается с помощью семантики передачи по указателю или, если возможно, с помощью интеллектуальных указателей.
Примечание
Важно настаивать на важности различия между ссылками на C ++ и Java. В C ++ ссылки концептуально являются экземпляром объекта, а не его средством доступа. Простейший пример - реализация функции подкачки:
Вышеприведенная функция swap изменяет оба аргумента, используя ссылки. Ближайший код на Java:
Java-версия кода изменит копии ссылок внутри, но не изменит фактические объекты извне. Java-ссылки - это C-указатели без арифметики указателей, которые передаются по значению в функции.
источник
Есть несколько случаев для рассмотрения.
Измененный параметр (параметры "out" и "in / out")
Этот случай в основном о стиле: вы хотите, чтобы код выглядел как call (obj) или call (& obj) ? Однако есть две точки, где разница имеет значение: необязательный случай, приведенный ниже, и вы хотите использовать ссылку при перегрузке операторов.
... и необязательно
Параметр не изменен
Это интересный случай. Практическое правило гласит, что типы «дешевого копирования» передаются по значению - обычно это небольшие типы (но не всегда), в то время как другие передаются по const ref. Однако, если вам нужно сделать копию внутри вашей функции независимо, вы должны передать по значению . (Да, это раскрывает некоторые детали реализации. C'est le C ++. )
... и необязательно
Здесь наименьшая разница между всеми ситуациями, так что выбирайте, что облегчит вашу жизнь.
Const by value - это деталь реализации
Эти объявления на самом деле точно такая же функция! При передаче по значению const - это просто деталь реализации. Попробуйте это:
источник
const
чтобы быть реализацией при передаче по значению.Передать по значению:
Передавайте переменные по значению, когда функции требуется полная изоляция от среды, т.е. чтобы функция не изменяла исходную переменную, а также чтобы другие потоки не могли изменять ее значение во время выполнения функции.
Недостатком являются циклы процессора и дополнительная память, затрачиваемая на копирование объекта.
Передать по константной ссылке:
Эта форма эмулирует поведение передачи по значению при удалении издержек копирования. Функция получает доступ на чтение к исходному объекту, но не может изменять его значение.
Недостатком является безопасность потоков: любое изменение, внесенное в исходный объект другим потоком, будет отображаться внутри функции, пока она еще выполняется.
Передать по неконстантной ссылке:
Используйте это, когда функция должна записать некоторое значение в переменную, которое в конечном итоге будет использовано вызывающей стороной.
Как и в случае с константным ссылочным кодом, он не является поточно-ориентированным.
Передать по константному указателю:
Функционально аналогичен передаче по const-reference, за исключением другого синтаксиса, плюс тот факт, что вызывающая функция может передавать указатель NULL, чтобы указать, что она не имеет допустимых данных для передачи.
Не потокобезопасен.
Передать по неконстантному указателю:
Аналогично неконстантной ссылке. Вызывающая сторона обычно устанавливает переменную в NULL, когда функция не должна записывать значение. Это соглашение встречается во многих API glibc. Пример:
Как и все, передаются по ссылке / указателю, а не потокобезопасны.
источник
Поскольку никто не упомянул, что я добавляю его, при передаче объекта в функцию в c ++ вызывается конструктор копирования объекта по умолчанию, если у вас нет такого объекта, который создает клон объекта и затем передает его в метод, поэтому когда вы изменяете значения объекта, которые будут отражаться на копии объекта, а не на исходном объекте, это является проблемой в c ++. Поэтому, если вы сделаете все атрибуты класса указателями, то конструкторы копирования будут копировать адреса атрибуты указателя, поэтому при вызове метода для объекта, который манипулирует значениями, хранящимися в адресах атрибутов указателя, изменения также отражаются в исходном объекте, который передается в качестве параметра, так что это может вести себя так же, как Java, но не забывайте, что весь ваш класс атрибуты должны быть указателями, также вы должны изменить значения указателей,будет очень ясно с объяснением кода.
Но это не очень хорошая идея, так как вы будете в конечном итоге писать много кода с указателями, которые подвержены утечкам памяти и не забывают вызывать деструкторы. И чтобы избежать этого, в C ++ есть конструкторы копирования, в которых вы будете создавать новую память, когда объекты, содержащие указатели, передаются в аргументы функций, которые прекратят манипулировать данными других объектов, Java действительно передает по значению, а значение является ссылкой, поэтому для него не требуются конструкторы копирования.
источник
Существует три способа передачи объекта в функцию в качестве параметра:
Просмотрите следующий пример:
Вывод:
источник
Ниже приведены способы передачи аргументов / параметров для работы в C ++.
1. по стоимости.
2. по ссылке.
3. по объекту.
источник