Reference (C ++) - Reference (C++)
![]() | tento článek potřebuje další citace pro ověření.listopad 2013) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |
V C ++ programovací jazyk, a odkaz je jednoduchý odkaz datový typ, který je méně výkonný, ale bezpečnější než ukazatel typ zděděný z C. Název C ++ reference může způsobit zmatek, protože v informatice je odkaz obecný pojem datový typ, s ukazatele a C ++ reference jako konkrétní implementace referenčních datových typů. Definice odkazu v C ++ je taková, že nemusí existovat. Může být implementován jako nový název pro existující objekt (podobně jako přejmenování klíčového slova v Adě).
Syntaxe a terminologie
Prohlášení o formuláři:
<Type>& <Name>
kde <Type>
je typ a <Name>
je identifikátor jehož typ je odkaz na <Type>
.
Příklady:
int A = 5;int& r_a = A;externí int& r_b;
Tady, r_a
a r_b
jsou typu "odkaz na" int
"
int& Foo();
Foo
je funkce, která vrací „odkaz na int
"
prázdnota Bar(int& r_p);
Bar
je funkce s referenčním parametrem, což je "odkaz na" int
"
třída Moje třída { int& m_b; /* ... */ };
Moje třída
je třída
s členem, na který se odkazuje int
int FuncX() { vrátit se 42 ; };int (&f_func)() = FuncX;
FuncX
je funkce, která vrací (nereferenční typ) int
a f_func
je alias pro FuncX
konst int& ref = 65;
konst int & ref
je konstantní reference ukazující na kus úložiště mající hodnotu 65.
Druhy, které jsou laskavé, odkazují na <Type>
„někdy se nazývají referenční typy. Identifikátory, které jsou referenčního typu, se nazývají referenční proměnné. Zavolat jim proměnná, nicméně, je ve skutečnosti nesprávné pojmenování, jak uvidíme.
Vztah k ukazatelům
Odkazy v C ++ se liší od ukazatelů několika základními způsoby:
- Po definování referenčního objektu není možné odkazovat přímo; jakýkoli výskyt jeho názvu odkazuje přímo na objekt, na který odkazuje.
- Jakmile je vytvořen odkaz, nelze jej později použít k odkazu na jiný objekt; to nemůže být znovu usazen. To se často provádí pomocí ukazatelů.
- Odkazy nemohou být nulavzhledem k tomu, že ukazatele mohou; každý odkaz odkazuje na nějaký objekt, i když může, ale nemusí být platný. Z tohoto důvodu nejsou kontejnery odkazů povoleny.
- Odkazy nelze neinicializovat. Protože je nemožné znovu inicializovat odkaz, musí být inicializovány, jakmile jsou vytvořeny. Zejména místní a globální proměnné musí být inicializovány tam, kde jsou definovány, a odkazy, které jsou datovými členy instancí třídy, musí být inicializovány v seznamu inicializátorů konstruktoru třídy. Například:
int& k; // kompilátor si bude stěžovat: chyba: `k 'deklarováno jako reference, ale není inicializováno
Mezi ukazateli a odkazy je jednoduchý převod: operátor address-of (&
) přinese ukazatel odkazující na stejný objekt při použití na referenci a odkaz, který je inicializován z dereference (*
) hodnoty ukazatele bude odkazovat na stejný objekt jako tento ukazatel, kde je to možné bez vyvolání nedefinovaného chování. Tato ekvivalence je odrazem typické implementace, která efektivně kompiluje odkazy do ukazatelů, které jsou implicitně dereferencovány při každém použití. I když tomu tak obvykle je, standard C ++ nenutí kompilátory implementovat odkazy pomocí ukazatelů.
Důsledkem toho je, že v mnoha implementacích může provozování proměnné s automatickým nebo statickým životem prostřednictvím odkazu, i když je syntakticky podobné přímému přístupu, zahrnovat operace skryté dereference, které jsou nákladné.
Také proto, že operace s odkazy jsou tak omezené, jsou mnohem snáze srozumitelné než ukazatele a jsou odolnější vůči chybám. Zatímco ukazatele lze učinit neplatnými prostřednictvím různých mechanismů, od přenášení nulové hodnoty přes aritmetiku mimo hranice k nelegálním sesíláním až po jejich výrobu z libovolných celých čísel, dříve platný odkaz se stane neplatným pouze ve dvou případech:
- Pokud se jedná o objekt s automatickou alokací, který jde mimo rozsah,
- Pokud se jedná o objekt uvnitř bloku dynamické paměti, který byl uvolněn.
První je snadno detekovatelný automaticky, pokud má odkaz statický rozsah, ale stále je problémem, pokud je odkaz členem dynamicky přiděleného objektu; druhý je obtížnější odhalit. Toto jsou jediné obavy týkající se referencí a jsou vhodně řešeny přiměřenou alokační politikou.
Použití referencí
- Kromě užitečné náhrady ukazatelů je jedna pohodlná aplikace odkazů v seznamech parametrů funkcí, kde umožňují předávání parametrů použitých pro výstup bez výslovného přijímání adres volajícím. Například:
prázdnota Náměstí(int X, int& out_result) { out_result = X * X;}
Následující hovor by pak umístil 9 palců y:
int y;Náměstí(3, y);
Následující volání by však dalo chybu kompilátoru, protože referenční parametry nejsou kvalifikovány konst
lze vázat pouze na adresovatelné hodnoty:
Náměstí(3, 6);
- Vrácení reference umožňuje přiřazení volání funkcí k:
int& Preinc(int& X) { vrátit se ++X; // "návrat x ++;" by se mýlil}Preinc(y) = 5; // stejné jako ++ y, y = 5
- V mnoha implementacích normální mechanismy předávání parametrů často znamenají nákladnou operaci kopírování pro velké parametry. Reference kvalifikované s
konst
jsou užitečný způsob předávání velkých objektů mezi funkcemi, který se vyhne této režii:prázdnota FSlow(BigObject X) { /* ... */ } prázdnota Rychle(konst BigObject& X) { /* ... */ }BigObject y;FSlow(y); // Pomalu, zkopíruje y do parametru x.Rychle(y); // Rychlý, poskytuje přímý přístup pouze pro čtení k y.
Li Rychle
ve skutečnosti vyžaduje vlastní kopii X že může upravit, musí explicitně vytvořit kopii. I když lze stejnou techniku použít pomocí ukazatelů, zahrnovalo by to úpravu každého místa volání funkce tak, aby přidávala těžkopádnou adresu (&
) operátory argumentu a bylo by stejně obtížné jej vrátit zpět, pokud by se objekt později zmenšil.
Polymorfní chování
Pokračování vztahu mezi odkazy a ukazateli (v kontextu C ++), první vykazují polymorfní schopnosti, jak by se dalo očekávat:
#zahrnout <iostream>třída A { veřejnost: A() = výchozí; virtuální prázdnota Tisk() { std::cout << „Tohle je třída A n"; }};třída B : veřejnost A { veřejnost: B() = výchozí; virtuální prázdnota Tisk() { std::cout << „Toto je třída B n"; }};int hlavní() { A A; A& ref_to_a = A; B b; A& ref_to_b = b; ref_to_a.Tisk(); ref_to_b.Tisk();}
Výše uvedený zdroj je platný C ++ a generuje následující výstup: Toto je třída A.
Toto je třída B
Definice ISO
Odkazy jsou definovány standardem ISO C ++ následujícím způsobem (s výjimkou ukázkové části):
V prohlášení T D, kde D má formu
& D1a typ identifikátoru v prohlášení T D1 je „seznam odvozených typů deklarátorů
T
, „pak typ identifikátoru D je“seznam odvozených typů deklarátorů odkaz naT
"Reference kvalifikované pro život jsou špatně vytvořené, kromě případů, kdy kvalifikace pro život (konst
a nestálý) jsou zavedeny pomocí atypedef
(7.1.3) nebo argumentu typu šablony (14.3), v takovém případě jsou kvalifikátory cv ignorovány. [Příklad: vtypedef int& A;konst A aref = 3; // špatně vytvořené;// non-const reference inicializovaná rvaluetyp
aref
je „odkaz naint
„, ne“konst
odkaz naint
". ] [Poznámka: o odkazu lze uvažovat jako o názvu objektu. ] Deklarátor, který určuje odkaz typu na životopis void "je špatně utvořen.Není uvedeno, zda reference vyžaduje úložiště (3.7).
Nesmí být žádné odkazy na odkazy, žádná pole odkazů a žádné odkazy na odkazy. Prohlášení o odkazu obsahuje: inicializátor (8.5.3) kromě případů, kdy prohlášení obsahuje explicitní
externí
specifikátor (7.1.1), je deklarace člena třídy (9.2) v deklaraci třídy, nebo je deklarace parametru nebo návratového typu (8.3.5); viz 3.1. Odkaz se inicializuje, aby odkazoval na platný objekt nebo funkci. [Poznámka: zejména nulový odkaz nemůže existovat v dobře definovaném programu, protože jediný způsob, jak takový odkaz vytvořit, je svázat jej s „objektem“ získaným dereferencí nulového ukazatele, který způsobí nedefinované chování. Jak je popsáno v 9.6, odkaz nelze vázat přímo na bitové pole. ]— ISO / IEC 14882: 1998 (E), standard ISO C ++, v části 8.3.2 [dcl.ref]