Már használtál és írtál C++ függvényeket néhány fogalomnál. Itt az ideje, hogy technikailag is belemenjünk. Az alábbi kódrészlet a leggyakoribb kifejezéseket mutatja be, hogy könnyen visszakereshesd őket. Mivel a C++ figyelmen kívül hagyja a whitespace-t, a formázást úgy alakítottuk át, hogy minden elem egy-egy külön sorba kerüljön.
// Function declaration:
bool // Return type
admin_detected(string user, string password) // Type signature
; // Don't forget the ';' for the declaration
// Function definition:
bool // Return type
admin_detected // Function name
(string user, string password) // Parameter list
{ return user == "admin" && password == "1234"; } // Function body
A deklaráció olyan, mint egy üzenet a fordítónak: létezik egy függvény ezzel a névvel, visszatérési típussal és paraméterlistával. A kód nem fog működni, ha hiányzik a definíció. A deklarációk elhagyhatók, akkor van rájuk szükség, ha a függvényt a definíciója előtt használod. A deklarációk megoldhatnak olyan problémákat, mint a körkörös hivatkozások, és arra is használhatók, hogy elválasszák a felületet a megvalósítástól.
Néha biztos szeretnél lenni benne, hogy az értékek a kezdeti értékadás után nem változtathatók meg.
A C++ a const kulcsszót használja a konstansok minősítőjeként.
const int number_of_dragon_balls{7};
number_of_dragon_balls--; // compilation error
A konstansokat gyakran UPPER_SNAKE_CASE írásmóddal látod majd. Ha nincs más konvenció, érdemes ezt az írásmódot a makróknak fenntartani.
Ha egy konstans változót a beállítása után megpróbálsz megváltoztatni, a kódod nem fog lefordulni. Ez segít elkerülni a nem szándékos változtatásokat, emellett optimalizálási lehetőségeket is nyit a fordító számára. Emberként is könnyebb átlátni a kódot, ha tudod, hogy bizonyos részek nem fognak változni.
A const-ot függvényparaméterek minősítőjeként is használhatod.
string guess_number(const int& secret, const int& guess) {
if (secret < guess) return "lower.";
if (secret > guess) return "higher.";
return "exact!";
}
Amikor egy const referenciát adsz át a függvénynek, biztos lehetsz benne, hogy az változatlan marad.
Gyakran látsz majd const referenciákat olyan objektumokhoz, amelyeket költséges lenne másolni, például hosszabb stringekhez.
A const minősítő harmadik felhasználási esete az olyan tagfüggvények, amelyek nem változtatják meg az osztály egy példányát.
class Stubborn {
public:
Stubborn(string reply) {
response = reply;
}
string answer(const string& question) const {
if (question.length() == 0) { return ""; }
return response;
}
private:
string response{};
};
A Stubborn answer tagfüggvénye const string& referenciát használ paraméterként.
Ez elkerüli a függvénynek átadott eredeti objektum másolását.
Több függvénynek is lehet ugyanaz a neve, ha a paraméterlistájuk különbözik. Ezt függvénytúlterhelésnek nevezzük, és általában akkor alkalmazzuk, ha ezek a függvények nagyon hasonló feladatokat látnak el.
A visszatérési típus nélküli függvényfejléc a függvény típusszignatúrája. A típusszignatúra megváltozása új függvényt eredményez.
A play_sound példának hat különböző túlterhelése van, hogy különböző helyzeteket lefedjen:
// different argument types:
void play_sound(char note); // C, D, E, ..., B
void play_sound(string solfege); // do, re, mi, ..., ti
void play_sound(int jianpu); // 1, 2, 3, ..., 7
// different number of arguments:
void play_sound(string solfege, double duration);
// different qualifiers:
void play_sound(vector<string>& solfege);
void play_sound(const vector<string>& solfege);
A típusszignatúrát a függvény neve, a paraméterek száma, típusa és minősítői határozzák meg (a nevük viszont nem). A visszatérési típus kifejezetten nem része a típusszignatúrának, és fordítási hibát kapsz, ha két függvényed csak a visszatérési típusban tér el. A fordító azért fog panaszkodni, mert nem egyértelmű, hogy a kettő közül melyiket kell használni.
Némelyik függvény nagyon hosszúra nyúlhat, és a hívásai közül sok ugyanazokat az értékeket használhatja a paraméterek többségéhez. Az ilyen hívásokban fellépő ismétlődést alapértelmezett argumentumokkal kerülheted el.
void record_new_horse_birth(string name, int weight, string color="brown-ish", string dam="Alruccaba", string sire="Poseidon");
record_new_horse_birth("Urban Sea", 130); // color will be brown, dam "Alruccabam", sire "Poseidon"
record_new_horse_birth("Highclere", 175, "off-white", "Fall Aspen"); // sire will be "Poseidon"
Mivel a függvénydeklarációt gyakran a definíció előtt olvassák, jobb hely az alapértelmezett argumentumok beállítására. Ha egy paraméternek van alapértelmezett deklarációja, akkor a tőle jobbra lévő összes paraméternek is szüksége van rá. Néha a bonyolult függvénytúlterhelések kevesebb, alapértelmezett argumentumokkal rendelkező függvényre refaktorálhatók a karbantarthatóság javítása érdekében.
Ebben a feladatban még egy kis kódot írsz, ami a kedvenc szakácskönyvedből származó remek lasagnéd elkészítéséhez és megsütéséhez kapcsolódik.
Öt részfeladat vár rád. Az első magával a sütéssel kapcsolatos, a másik négy a tökéletes előkészületről szól.
A következő lasagnához, amit elkészítesz, szeretnél elegendő időt félretenni, hogy nyugodtan élvezhesd a főzést. Már megtervezted, milyen rétegekből áll majd a lasagnéd. Most ebből szeretnéd megbecsülni, mennyi ideig tart majd az előkészület.
Készíts egy preparationTime függvényt, amely egy rétegekből álló vektort fogad string típusként, valamint a rétegenkénti átlagos előkészítési időt percben, int típusként.
A függvény a rétegek száma alapján adja vissza a teljes előkészítési idő becslését int típusként.
Ha nem adják meg az átlagos előkészítési időt, akkor a 2 alapértelmezett értéket kell használni.
std::vector<std::string> layers{"sauce", "noodles", "sauce", "meat", "mozzarella", "noodles"};
preparationTime(layers, 3)
// => 18
preparationTime(layers)
// => 12
Az idő félretétele mellett szeretnél arról is gondoskodni, hogy legyen elég szósz és tészta az álmaid lasagnájához. A lasagnád minden tésztarétegéhez 50 gramm tésztára lesz szükséged. Minden szószréteghez 0,2 liter szószra lesz szükséged.
Definiáld a quantities függvényt, amely paraméterként egy rétegekből álló vektort fogad string típusként.
A függvény ezután meghatározza az étel elkészítéséhez szükséges tészta- és szószmennyiséget.
Az eredményt amount struct formájában kell visszaadni, amelyet már definiáltunk neked.
Az amount két tagváltozóval rendelkezik: az egyik a noodles tömegét tárolja int típusként, a második a sauce térfogatát double típusként.
struct amount { int noodles; double sauce; };
amount needed{quantities({"sauce", "noodles", "sauce", "meat", "mozzarella", "noodles"})};
// needed.noodles => 100
// needed.sauce => 0.4
Nemrég meglátogattál egy barátodat, és lasagnát ettél nála. Fantasztikus volt, és volt benne valami különleges. A barátod elküldte a hozzávalók listáját, és azt mondta, hogy a lista utolsó eleme a „titkos hozzávaló”, amitől az étel olyan különleges lett. Most te is hozzá szeretnéd adni ezt a titkos hozzávalót a receptedhez.
Írj egy addSecretIngredient függvényt, amely két vector of strings paramétert fogad.
Az első paraméter a saját recepted hozzávalóira mutató referencia, a második vektor pedig a barátod által küldött hozzávalókat tartalmazza.
A hozzávalólistád utolsó eleme mindig "?".
A függvény helyettesítse ezt a barátod listájának utolsó elemévvel.
Megjegyzés: az addSecretIngredient nem ad vissza semmit, helyette közvetlenül a saját hozzávalóid listáját kell módosítanod.
A barátod hozzávalóit tartalmazó lista szintén lehet referencia (a teljesítmény javítása érdekében), de nem szabad módosítani.
Ügyelj rá, hogy a lista const referenciával ne módosuljon.
std::vector<std::string> friendsList{"noodles", "sauce", "mozzarella", "kampot pepper"};
std::vector<std::string> myList{"noodles", "meat", "sauce", "mozzarella", "?"};
addSecretIngredient(myList, friendsList);
// myList => {"noodles", "meat", "sauce", "mozzarella", "kampot pepper"}
A szakácskönyvedben felsorolt mennyiségek csak két adag lasagnához elegendőek. Mivel legközelebb több emberre szeretnél főzni, szeretnéd kiszámítani a mennyiségeket különböző adagszámokhoz.
Készíts egy scaleRecipe függvényt, amely két paramétert fogad.
double értékekből álló vektor a 2 adaghoz szükséges mennyiségekkel.A függvény egy új vektort adjon vissza a kívánt adagszámhoz szükséges mennyiségekkel.
Az eredeti receptet viszont meg szeretnéd tartani.
Ez azt jelenti, hogy a quantities argumentumot ebben a függvényben nem szabad módosítani.
std::vector<double> quantities{1.2, 3.6, 10.5};
scaleRecipe(quantities, 4);
// => { 2.4, 7.2, 21 }
Emlékszel gyerekkori történetekre, mesékre a dédnagynénédről, aki a család legmélyebb kulináris titkainak őrzője. A legenda szerint nála van a kulcs az elképzelhetetlen ízek feloldásához, de a módszerei szokatlanok. Nem foglalkozik listákkal vagy mérésekkel; suttogva beszél, és egyszerre csak egy hozzávalót árul el.
Izgalom és szorongás keverékével úgy döntesz, hogy felveszed a kapcsolatot a dédnagynénéddel. Ahogy vártad, rejtélyes modorában válaszol, és egyetlen titkos hozzávalót kínál, misztériumba burkolva.
A dédnagynénéd hozzájárulása egy újabb réteget ad a bonyolultsághoz, amit szeretnél felhasználni a receptedben.
Készítsd el az addSecretIngredient függvény egy másik változatát, amely két argumentumot fogad: egy referenciát a hozzávalóid listáját képviselő vektorra, és egyetlen stringet, amely a dédnagynénéd rejtélyes ajándékát képviseli.
std::vector<std::string> myList{"noodles", "meat", "sauce", "mozzarella", "?"};
std::string secretIngredient{"spice melange"};
addSecretIngredient(myList, secretIngredient);
// myList => {"noodles", "meat", "sauce", "mozzarella", "spice melange"}
Sok szerencsét, bátor séf!
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) C++ nyelvet 19 fogalom100 feladat segítségével, valódi emberi mentorálással, mindez ingyen.