20. szabály inkább elhaladó hivatkozással const elhaladó érték - hatékony

20. szabály: Inkább elhaladó hivatkozással const elhaladó értéke

Alapértelmezésben a C ++ objektumok függvénynek adjuk át, és visszaadja a függvény értékének (ingatlan örökölt C). Ha másként nem jelöljük, a paramétereket a funkció inicializálva példányban valódi érvek, és a függvény hívása után, a program másolatot kap a visszaadott érték egy függvény. Másolatok egy példányát kivitelező. Ezért átvitel lehet értelmesen szállítmány működését. Vegyük például a következő osztály hierarchiát:

Személyi (); // paramétereket az egyszerűség kedvéért elhagytuk

Személyi (); // lásd 7. cikk -. Miért virtuális

osztály Student: nyilvános Person

Student (); // paraméterek itt eltekintünk

Most nézd meg az alábbi kódot, amely az úgynevezett validateStudent funkciója, amely során egy érv Student (értékben), és visszaadja a jele annak helyességét:

bool validateStudent (Student s); // függvény

// Student érték szerint

Student plato; // Platón Szókratész tanult

bool platoIsOk = validateStudent (plato); // a függvényt

Mi történik, ha ezt a funkciót?

Nyilvánvaló, hogy a Student másolat kivitelező hívják elindítani a paraméter plato. Az is világos, hogy az S megsemmisült, amikor visszatér a érvényesítse-Student. Ezért az átviteli paraméter értékét tekintve ez a funkció kerül egy hívás Student copy konstruktor és destruktor hívás Student.

De ez még nem minden. Student objektum tartalmazza önmagán belül két tárgy: string, így minden alkalommal, amikor össze egy hallgató objektumot is meg kell építeni, és ezt a két tárgyat. Student osztály örökli az osztály Person, így minden alkalommal, tervezése Student objektum, meg kell tervezni, és Person objektum. De egy ember objektum két string objektumot, így minden egyes személy építési jár két hívás húr kivitelező. Így átadása Student objektum értékét vezet az egyik hívás Student példányt kivitelező, másolja konstruktor hívást egy személy, és négy hívást húr konstruktorok másolata. Amikor egy példányát a hallgató objektum megszűnik, minden konstruktor hívást felel destructor hívást, így a teljes költsége a Student érték szerint átadott hat konstruktőri és hat destruktorok!

Nos, ez a helyes és kívánatos viselkedést. A nap végén, akkor szeretné, hogy minden objektum pontos kezdeti és megsemmisítik. Mégis jó lenne megtalálni a módját, hogy kihagyja az összes ezeket a hívásokat konstruktorok és a destruktor. Van egy út! Ez - múló hivatkozva állandó:

bool validateStudent (const Student s);

A referencia paraméter is elkerüli a „vágás” a probléma (szeletelés). Amikor a származtatott osztály objektum át (érték szerint), mint egy alap osztály objektum konstruktor nevezzük másolása alap osztályt, és ezeket a részeket tartozó származék „cut off”. Csak van egy egyszerű alap osztály objektum - ami egészen természetes, hiszen létrehoztunk egy alap osztály konstruktora. Ez szinte mindig nincs, amire szüksége van. Tegyük fel például, ön dolgozik egy sor osztályok, hogy végre egy grafikus ablak rendszer:

std :: string name () const; // visszaadja az ablak neve

virtuális void kijelző () const; // felhívni ablak és a tartalom

osztály WindwoWithScrollBars: nyilvános Window

virtuális void kijelző () const;

Minden osztály ablak objektumnak van egy név, amely lehet átjutni a funkció nevét, és az ablakokat is megjelenik, amint azt a jelen kijelző funkciók. Az a tény, hogy a kijelző - egy virtuális függvény, azt mondja, hogy a megjelenítési mód egyszerű tárgyak alap osztály Window eltérhet a megjelenítésre tárgyak WindowWithScrollBar (lásd szabályok 34. és 36.).

Tételezzük fel, hogy szeretne írni egy függvényt, amely kiírja a nevét, az ablakot, majd jelenítse meg. Ez a rossz irányba, hogy írjon egy ilyen funkció:

void printNameAndDisplay (Window w) // rossz! paraméter

Lássuk, mi történik, ha ezt a funkciót, átadva azt a tárgyat WindowWithScrollBar:

w paraméter kerül kialakításra - amint azokat értéket, nem emlékszel? - a Window objektumot, és minden további információt, amely köti azt WindowWithScrollBar, akkor levágja. Belül printNameAndDisplay w mindig úgy viselkednek, mint egy objektum osztály Window (mert ez egy objektum osztály Window), függetlenül attól, hogy milyen típusú az objektum ténylegesen át a funkciót. Különösen a hívás kijelző funkció belül printNameAndDisplay mindig okoz Window :: kijelző, soha - WindowWithScrollBar :: kijelzőn.

Remedy „vágás” - w szerint átadott állandó:

void printNameAndDisplay (const Window w) // helyes opciót

Most w viselkedik rendesen, nem számít, hogy mit jelenthet egy ablak valóra.

Ha megnézzük „a motorháztető alatt» C ++, látni fogja, hogy a hivatkozások általában megvalósítva mutatók, így a átadása valami hivatkozással általában azt jelenti, a szállítási mutatót. Ennek eredményeként, a beágyazott típusú objektumok (például int) mindig hatékonyabban továbbítja érdemben mint hivatkozunk. Ezért a beépített típusok, ha van egy választás -, hogy adja át az érték alapján, vagy állandó, akkor van értelme, hogy válasszon egy érték szerint átadott. Ugyanez vonatkozik a tanácsot iterátorokat és funkciója tárgyak STL, mert kifejezetten az értéke transzferek. Alkalmazó programozó iterátorokat és függvény objektumok, amelyek felelősek, hogy biztosítsák az átviteli hatékonyságának értékük, és kizárja az „Cut”. Ez egy példa arra, hogyan szabályok megváltoznak függően a rész, C ++ (cm., 1. általában).

Ha kis tárgyak olcsón konstruktorok másolata, akkor is hatással a teljesítményre. Néhány fordító kezelhetik beépített és felhasználó által definiált típusok különböző módon, még ha ugyanaz a belső ábrázolása. Például néhány fordító ne tegyen, amely csak egy dupla a nyilvántartásokban, akkor is, ha hajlandók olyan értéket beépített típusú kettős. Ilyen esetekben jobb átadni tárgyakat hivatkozással, mert a fordító minden bizonnyal hajlandó tenni a nyilvántartásban mutató (amely végrehajtja a link).

A másik ok, amiért a kis felhasználó által definiált típusok nem feltétlenül jó az átviteli érték abban rejlik, hogy a méretük is változik. Típus, amely kicsi ma emelkedhet a jövőben, mert a belső megvalósítása változhat. A helyzet változóban van, akkor is, ha átvált egy másik végrehajtását C ++. Például egyes megvalósítások, a string típusú a szabványos könyvtár hétszer nagyobb, mint a többiek.

Általánosságban elmondható, hogy az egyetlen fajta, melyek abból lehet kiindulni, hogy az átruházás értékét lesz olcsó - ez a beépített típusok, valamint iterátorokat és STL függvény objektumok. Minden mást, kövesse a szabályokat és át paramétereket, hivatkozva egy állandó érték, hanem a sebességváltó.