Reference (C++)Reference v programovacím jazyce C++ je konstrukce, která vytváří jiné jméno pro objekt (proměnnou nebo funkci).[pozn. 1] Reference se obvykle používají jako parametry funkce. Deklarují se stejným stylem jako ukazatele, ale místo symbolu Reference poskytuje podobnou funkčnost jako ukazatel z jazyka C, ale je bezpečnější. Reference musí být vždy inicializovaná, a nemůže být přesměrována na jiný objekt. Další výhodou je kompaktnější zápis; všude jinde než v deklaraci se používá pouze jméno; kdyby byly použity ukazatele, bylo by nutné v těle funkce používat dereference a ve volání funkce operátor Název reference může způsobovat nedorozumění, protože v matematické informatice je reference obecný koncept datového typu, jehož konkrétní implementací je ukazatel i zde popisovaná C++ reference. Syntaxe a terminologieLvalue referenceDeklarace tvaru: typ& identifikátor deklaruje identifikátor typu lvalue reference na zadaný typ.[1] Příklady: int a = 5;
int& r_a = a;
extern int& r_b;
int& Foo();
void Bar(int& r_p);
class MyClass { int& m_b; /* ... */ };
int FuncX() { return 42 ; };
int (&f_func)() = FuncX;
int (&&f_func2)() = FuncX; // v zásadě totéž jako předchozí
const int& ref = 65;
int arr[3];
int (&arr_lvr)[3] = arr;
int (&&arr_rvr)[3] = std::move(arr);
typedef int arr_t[3];
int (&&arr_prvl)[3] = arr_t{}; // arr_t{} je prvalue typu pole
int *const & ptr_clv = arr; // totéž jako int *const & ptr_clv = &arr[0];
int *&& ptr_rv = arr;
// int *&arr_lv = arr; // Chyba: inicializace lvalue reference na nekonstantní typ pomocí rvalue
int FuncX() { return 42 ; };
int (*const &pf_func)() = FuncX; // totéž jako int (*const &pf_func)() = &FuncX;
int (* &&pf_func2)() = FuncX;
Rvalue referenceDeklarace tvaru: typ&& identifikátor deklaruje identifikátor typu rvalue reference na zadaný typ.
Protože jméno rvalue reference je samo o sobě lvalue, je třeba použít Typy, které jsou referencemi na nějaký typ, se někdy nazývají referenční typy. Identifikátory, které jsou referenčního typu se nazývají referenční proměnné, přestože to není příliš vhodné pojmenování, jak uvidíme dále. Význam a omezeníReference nejsou objekty a mohou se odkazovat pouze na objekty nebo funkce. Nemůže existovat pole referencí, protože pole se musí skládat z objektů. Stejně tak nemohou existovat ukazatele na referenci a reference na referenci, protože ukazatel musí ukazovat na objekt a reference se musí odkazovat na objekt. To znamená, že Reference nemohou být int i;
typedef int& LRI;
using RRI = int&&;
LRI& r1 = i; // r1 je typu int&
const LRI& r2 = i; // r2 je typu int&
const LRI&& r3 = i; // r3 je typu int&
RRI& r4 = i; // r4 je typu int&
RRI&& r5 = 5; // r5 je typu int&&
decltype(r2)& r6 = i; // r6 je typu int&
decltype(r2)&& r7 = i; // r7 je typu int&
Nestatickou členskou funkci lze deklarovat s kvalifikátorem #include <iostream>
struct A
{
A() = default;
void Print()const& { std::cout << "lvalue\n"; }
void Print()const&& { std::cout << "rvalue\n"; }
};
int main()
{
A a;
a.Print(); // vypíše "lvalue"
std::move(a).Print(); // vypíše "rvalue"
A().Print(); // vypíše "rvalue"
A&& b = std::move(a);
b.Print(); // vypíše "lvalue"(!)
}
Vztah k ukazatelůmReference v C++ se v několika ohledech liší od ukazatelů:
Reference, které jsou samostatnými lokálními nebo globálními proměnnými, musejí být inicializovány ve své definici; a reference, které jsou datovými členy instance třídy, musejí být inicializovány v seznamu inicializátorů konstruktoru třídy. Například:
Mezi ukazateli a referencemi existuje jednoduchý převod: operátor To má za následek, že v mnoha implementacích práce s proměnnými s automatickou nebo statickou životností pomocí referencí může způsobovat skryté operace dereference, které, i když se syntakticky podobají přímému přístupu, jsou nákladné. Protože operace s referencemi jsou tak omezené, je mnohem snazší rozumět referencím než ukazatelům a použití referencí je také odolnější proti chybám. Zatímco ukazatel je možné zneplatnit mnoha mechanismy, od použití hodnoty
První případ lze snadno automaticky detekovat, pokud má reference statický rozsah platnosti, ale představuje to problém, pokud reference je členem dynamicky alokovaného objektu; druhý případ se detekuje obtížněji. To jsou jediné problémy s referencemi, které lze řešit rozumnou strategií přidělování paměti. Použití referencíNejobvyklejším použitím referencí je pro (formální) parametry funkcí. Reference umožňují číst i měnit hodnoty argumentů (skutečných parametrů) funkcí, aniž by bylo třeba při každém použití parametru použít operátor dereference void Square(int x, int& out_result) {
out_result = x * x;
}
Vyvolání této funkce s argumenty int y;
Square(3, y);
Pokus vyvolat tuto funkci s celočíselným literálem jako druhým argumentem způsobí chybu překladu, protože parametry, které jsou lvalue referencemi bez Square(3, 6);
Volání funkce, která vrací lvalue referenci, je možné použít na levé straně přiřazovacího příkazu: int& Preinc(int& x) {
return ++x; // "return x++;" je špatně
}
Preinc(y) = 5; // totéž jako ++y, y = 5
Předávání parametrů vyžaduje v mnoha implementacích nákladné operace kopírování velkých parametrů. Pokud je parametr reference s void FSlow(BigObject x) { /* ... */ }
void FFast(const BigObject& x) { /* ... */ }
BigObject y;
FSlow(y); // Pomalé, kopíruje y do parametru x.
FFast(y); // Rychlé, poskytuje přímý přístup k y (pouze pro čtení).
Pokud by funkce Polymorfní chováníPři srovnání referencí a ukazatelů (v jazyce C++), mají reference polymorfní funkcionalitu: #include <iostream>
class A {
public:
A() = default;
virtual void Print() { std::cout << "This is class A\n"; }
};
class B : public A {
public:
B() = default;
virtual void Print() { std::cout << "This is class B\n"; }
};
int main() {
A a;
A& ref_to_a = a;
B b;
A& ref_to_b = b;
ref_to_a.Print();
ref_to_b.Print();
}
Tento program vypíše: This is class A
This is class B
OdkazyPoznámky
ReferenceV tomto článku byl použit překlad textu z článku Reference (C++) na anglické Wikipedii.
Externí odkazy
|
Portal di Ensiklopedia Dunia