Існують деякі відмінності у викликах конвенцій у C ++ та Java. В C ++ технічно говорять лише дві конвенції: прохідна вартість і пропускна посилання, з деякою літературою, включаючи третю конвенцію прохідного вказівника (що є фактично прохідним значенням типу вказівника). Крім того, ви можете додати доцільність до типу аргументу, посилюючи семантику.
Перейти за посиланням
Перехід за посиланням означає, що функція концептуально отримає ваш об'єкт об'єкта, а не його копію. Посилання концептуально є псевдонімом об'єкта, який використовувався в контексті виклику, і не може бути нульовим. Усі операції, що виконуються всередині функції, стосуються об'єкта поза функцією. Ця конвенція недоступна на Java або C.
Передача за значенням (і прохідний вказівник)
Компілятор генерує копію об'єкта в контексті виклику і використовує цю копію всередині функції. Усі операції, що виконуються всередині функції, виконуються над копією, а не зовнішнім елементом. Це умова для примітивних типів на Java.
Спеціальна його версія - це передача покажчика (адреси-об’єкта) у функцію. Функція отримує вказівник, і всі операції, застосовані до самого вказівника, застосовуються до копії (вказівника), з іншого боку, операції, застосовані до вказівника відміни, застосовуватимуться до об'єкта об'єкта в цьому місці пам'яті, тому функція може мати побічні ефекти. Ефект від використання прохідного значення вказівника на об’єкт дозволить внутрішній функції змінювати зовнішні значення, як при передачі посилання, а також дозволить отримати необов'язкові значення (передайте нульовий покажчик).
Це умова, застосовувана в C, коли функції потрібно змінити зовнішню змінну, і конвенція, що використовується в Java з еталонними типами: посилання скопійовано, але зазначений об'єкт той самий: зміни в довідці / покажчику не видно зовні функція, але зміни в загострену пам'ять є.
Додавання рівняння до рівняння
У C ++ ви можете призначити константу ness об'єктам при визначенні змінних, покажчиків та посилань на різних рівнях. Ви можете оголосити змінну постійною, ви можете оголосити посилання на постійний екземпляр, а також можна визначити всі вказівники на постійні об'єкти, постійні вказівники на об'єкти, що змінюються, і постійні вказівники на постійні елементи. І навпаки, у Java ви можете визначити лише один рівень константи-ness (остаточне ключове слово): рівень змінної (екземпляр для примітивних типів, посилання на типи посилань), але ви не можете визначити посилання на незмінний елемент (якщо тільки сам клас не непорушний).
Це широко використовується у конвенціях про виклики C ++. Коли об’єктів мало, ви можете передати об'єкт за значенням. Компілятор створить копію, але ця копія не є дорогою операцією. Для будь-якого іншого типу, якщо функція не змінить об'єкт, ви можете передати посилання на постійний екземпляр (зазвичай називається постійним посиланням) типу. Це не скопіює об’єкт, а передасть його у функцію. Але в той же час компілятор гарантує, що об'єкт не буде змінений всередині функції.
Емпіричні правила
Ось кілька основних правил, яких слід дотримуватися:
- Віддайте перевагу прохідному значенню для примітивних типів
- Віддайте перевагу проходженню з посиланнями на постійні для інших типів
- Якщо функції потрібно змінити аргумент, використовуйте пропускний посилання
- Якщо аргумент необов’язковий, використовуйте прохідний вказівник (до постійного, якщо необов'язкове значення не слід змінювати)
Існують і інші невеликі відхилення від цих правил, перше з яких - обробка права власності на об'єкт. Коли об'єкт динамічно виділяється новим, він повинен бути розміщений з видаленням (або [] його версіями). Об'єкт або функція, що відповідає за знищення об'єкта, вважається власником ресурсу. Коли динамічно виділений об'єкт створюється в фрагменті коду, але право власності передається іншому елементу, зазвичай це робиться за допомогою семантики прохідних покажчиків або, якщо можливо, за допомогою розумних покажчиків.
Бічна примітка
Важливо наполягати на важливості різниці між посиланнями C ++ та Java. У посиланнях C ++ концептуально є екземпляр об'єкта, а не його доступ. Найпростіший приклад - реалізація функції swap:
// C++
class Type; // defined somewhere before, with the appropriate operations
void swap( Type & a, Type & b ) {
Type tmp = a;
a = b;
b = tmp;
}
int main() {
Type a, b;
Type old_a = a, old_b = b;
swap( a, b );
assert( a == old_b );
assert( b == old_a );
}
Вищенаведена функція swap змінює обидва аргументи за допомогою використання посилань. Найближчий код на Java:
public class C {
// ...
public static void swap( C a, C b ) {
C tmp = a;
a = b;
b = tmp;
}
public static void main( String args[] ) {
C a = new C();
C b = new C();
C old_a = a;
C old_b = b;
swap( a, b );
// a and b remain unchanged a==old_a, and b==old_b
}
}
Версія Java-коду змінює копії посилань всередині країни, але не змінює фактичні об'єкти зовні. Посилання Java - це покажчики C без арифметики вказівника, які передаються за значенням у функції.