Video: C++ Tutorial for Beginners - Full Course 2024
Door Stephen R. Davis
C ++ is geen gemakkelijke programmeertaal om te beheersen. Alleen door ervaring zullen de ontelbare combinaties van symbolen voor jou vanzelfsprekend lijken. Deze Cheat Sheet geeft je echter enkele stevige tips om die overgang van C ++ beginner naar C ++ goeroe te vergemakkelijken: Weet hoe je complexe C ++ -uitdrukkingen moet lezen; leren hoe wij aanwijzerproblemen kunnen voorkomen; en uitzoeken hoe en wanneer diepe kopieën moeten worden gemaakt.
Hoe een complexe C ++ - expressie
lezen C ++ staat vol kleine symbolen, die elk bijdragen aan de betekenis van uitdrukkingen. De regels van de C ++ grammatica zijn zo flexibel dat deze symbolen kunnen worden gecombineerd in bijna oneindig complexe combinaties. Uitingen in de eenvoudigere C-taal kunnen zo stompzinnig worden dat er een jaarlijkse wedstrijd was voor wie het meest obscure programma kon schrijven en wie het kon begrijpen.
Het is nooit een goed idee om complexe code te schrijven, maar je zult soms uitdrukkingen tegenkomen in C ++ die op het eerste gezicht een beetje verbijsterend zijn. Gebruik de volgende stappen om erachter te komen:
-
Begin met de meest ingesloten haakjes.
Begin met zoeken naar de buitenste haakjes. Zoek binnen die, naar ingesloten haakjes. Herhaal het proces totdat u zich tot het diepste paar haakjes hebt gewerkt. Begin eerst met het evalueren van die subexpressie met behulp van de volgende regels. Zodra je die uitdrukking begrijpt, spring je terug naar het volgende niveau en herhaal je het proces.
-
Beoordeel elke bewerking binnen het paar haakjes in volgorde van prioriteit.
De volgorde waarin operatoren worden geëvalueerd, wordt bepaald door de prioriteit van de operator in de tabel. Indirectie komt vóór vermenigvuldiging die vóór toevoeging komt, dus voegt het volgende 1 plus 2 maal de waarde toe waarnaar wordt verwezen door * ptr.
int i = 1 + 2 * * ptr;
Prioriteit | Operator | Betekenis |
---|---|---|
1 | () (unary) | Een functie |
2 | * en -> (unary) | Dereference a pointer |
2 | - (unary) | Retourneert het negatief van het argument |
3 | ++ (unary) | Increment |
3 > - (unary) | Afname | 4 |
* (binair) | Vermenigvuldiging | 4 |
/ (binair) | Onderverdeling | 4 |
% (binair) | Modulo | 5 |
+ (binair) | Optelling | 5 |
- (binair) | Aftrekken | 6 |
&& (binair) | Logisch EN | 6 |
! ! | Logisch OF | 7 |
=, * =,% =, + =, - = (speciaal) | Toewijzingstypen | Bewerk operaties van dezelfde prioriteit van links naar rechts (behalve toewijzing, wat de andere kant op gaat). |
-
De meeste exploitanten met dezelfde prioriteit evalueren van links naar rechts. Dus het volgende voegt 1 op 2 toe en voegt het resultaat toe aan 3:
int i = 1 + 2 + 3;
De volgorde van evaluatie van sommige operatoren doet er niet toe. Additie werkt bijvoorbeeld hetzelfde van links naar rechts als van rechts naar links. De volgorde van evaluatie maakt veel verschil voor sommige bewerkingen zoals divisie. Het volgende verdeelt 8 bij 4 en verdeelt het resultaat met 2:
int i = 8/4/2;
De belangrijkste uitzondering op deze regel is toewijzing, die van rechts naar links wordt geëvalueerd:
a = b = c;
Hiermee worden c naar b en het resultaat toegewezen aan a.
Evalueer subexpressies in willekeurige volgorde.
-
Beschouw de volgende expressie:
int i = f () + g () * h ();
Vermenigvuldiging heeft een hogere prioriteit, dus je zou kunnen aannemen dat de functies g () en h () vóór f () worden aangeroepen, maar dit is niet het geval. Functieaanroep heeft de hoogste prioriteit van alle, dus alle drie de functies worden aangeroepen voordat de vermenigvuldiging of de toevoeging wordt uitgevoerd. (De resultaten geretourneerd door g () en h () worden vermenigvuldigd en vervolgens toegevoegd aan de resultaten geretourneerd door f ().)
De enige keer dat de volgorde waarin functies worden aangeroepen een verschil maakt, is wanneer de functie bijwerkingen heeft zoals het openen van een bestand of het wijzigen van de waarde van een globale variabele. U moet uw programma's zeker niet schrijven, zodat ze afhankelijk zijn van dit soort bijwerkingen.
Voer alleen typeconversies uit als dat nodig is.
-
U moet niet meer typen conversies uitvoeren dan absoluut noodzakelijk. De volgende expressie heeft bijvoorbeeld ten minste drie en mogelijk vier typeconversies:
float f = 'a' + 1;
Het teken 'a' moet worden gepromoveerd tot een int om de toevoeging uit te voeren. De int wordt vervolgens geconverteerd naar een dubbele en vervolgens omlaag geconverteerd naar een enkele precisie-zwevend. Onthoud dat alle rekenkundige bewerkingen int of dubbel worden uitgevoerd. Over het algemeen moet u voorkomen rekenkundige bewerkingen uit te voeren bij tekentypen en te voorkomen dat één precisie geheel zweeft.
5 manieren om aanwijzerproblemen te vermijden in C ++
In C ++ is een
-aanwijzer een variabele die het adres van een object in het interne geheugen van de computer bevat. Gebruik deze stappen om problemen met verwijzingen in C ++ te voorkomen: Initialiseer pointers wanneer deze worden gedeclareerd.
-
Laat pointervariabelen niet geïnitialiseerd - dingen zouden niet zo erg zijn als niet-geïnitialiseerde pointers altijd willekeurige waarden bevatten - de overgrote meerderheid van willekeurige waarden zijn illegale pointerwaarden en zorgen ervoor dat het programma crasht zodra ze worden gebruikt. Het probleem is dat niet-geïnitialiseerde variabelen de neiging hebben de waarde aan te nemen van andere, eerder gebruikte pointervariabelen. Deze problemen zijn heel moeilijk te debuggen.
Als u niet weet wat anders nog een pointer moet initialiseren, initialiseer het dan naar nullptr. nullptr is gegarandeerd een illegaal adres.
Geen verwijzingen meer nadat u ze hebt gebruikt.
-
Evenzo, altijd nul een pointer-variabele zodra de pointer niet langer geldig is door hem de waarde nullptr toe te kennen. Dit is met name het geval wanneer u een blok geheugen naar de heap terugstuurt met delete; altijd nul de aanwijzer na het ophalen van het heap-geheugen.
Wijs geheugen toe uit de heap en breng het terug naar de heap op hetzelfde "niveau" om geheugenlekken te voorkomen.
-
Probeer altijd een geheugenblok naar de heap terug te sturen op hetzelfde abstractieniveau als je het hebt toegewezen. Dit betekent in het algemeen dat u probeert om het geheugen op hetzelfde niveau van functieaanroepen te wissen.
Vang een uitzondering om het geheugen te verwijderen wanneer nodig.
-
Vergeet niet dat een uitzondering bijna altijd kan voorkomen. Als u van plan bent om de uitzondering te vangen en verder te werken (in tegenstelling tot het laten crashen van het programma), moet u ervoor zorgen dat u de uitzondering ophaalt en eventuele geheugenblokken naar de heap terugzet voordat de wijzers die erop wijzen buiten het bereik vallen en het geheugen is verloren.
Zorg ervoor dat de typen exact overeenkomen.
-
Zorg er altijd voor dat de soorten aanwijzers overeenkomen met het vereiste type. Zet een aanwijzer niet opnieuw zonder een specifieke reden. Beschouw het volgende:
void fn (int * p); void myFunc () {char c = 'a'; char * pC = & c; fn ((int *) pC);}
De bovenstaande functie compileert zonder klacht aangezien de karakterwijzer pC herschikt is naar een int * om overeen te komen met de declaratie van fn (int *); dit programma zal echter bijna niet werken. De functie fn () verwacht een wijzer naar een volledig 32-bits geheel getal en niet een of ander rinky-dink 8-bits teken. Dit soort problemen is erg moeilijk om uit te zoeken.
Hoe en wanneer diepe kopieën maken in C ++
Klassen die bronnen toewijzen aan hun constructor moeten normaal een kopieconstructor bevatten om kopieën van deze bronnen te maken. Het toewijzen van een nieuw geheugenblok en het kopiëren van de inhoud van het origineel naar dit nieuwe blok wordt een
diepe kopie (in tegenstelling tot de standaard ondiepe kopie) genoemd. Gebruik de volgende stappen om te bepalen hoe en wanneer diepe kopieën moeten worden gemaakt in C ++: Maak altijd een deep-kopie als de constructor bronnen toewijst.
-
Standaard maakt C ++ zogenaamde "oppervlakkige" kopieën van objecten van leden wanneer ze deze doorgeven aan functies of als resultaat van een opdracht. U moet de standaard ondiepe-kopie-operators vervangen door hun deep-kopie-equivalent voor elke klasse die bronnen toewijst aan de constructor. De meest gebruikte bron die wordt toegewezen is het heap-geheugen dat wordt geretourneerd door de nieuwe operator.
Neem altijd een destructor op voor een klasse die bronnen toewijst.
-
Als u een constructor maakt die bronnen toewijst, moet u een destructor maken die deze herstelt. Geen uitzonderingen.
Declareer de destructor altijd virtueel.
-
Een veel voorkomende beginnerfout is om te vergeten uw destructor virtueel te verklaren. Het programma loopt prima totdat een nietsvermoedende programmeur langskomt en erft van je klas. Het programma lijkt nog steeds te werken, maar omdat de destructor in de basisklasse mogelijk niet correct wordt aangeroepen, lekt het geheugen uit je programma als een zeef totdat het uiteindelijk crasht. Dit probleem is moeilijk te vinden.
Neem altijd een exemplaarconstructor mee voor een klasse die bronnen toewijst.
-
De kopie-constructor maakt een juiste kopie van het huidige object door geheugen van de stapel te scheiden en de inhoud van het bronobject te kopiëren.
Overschrijf altijd de toewijzingsoperator voor een klasse die bronnen toewijst.
-
Programmeurs moeten worden ontmoedigd door dwingende operators, maar de operator assignment is een uitzondering. U moet de toewijzingsoperator overschrijven voor elke klasse die resources in de constructor toewijst.
De toewijzingsoperator moet drie dingen doen:
Zorg ervoor dat het linker- en rechterhandobject niet hetzelfde object zijn. Met andere woorden, zorg ervoor dat de toepassingsprogrammeur niet zoiets heeft geschreven als (a = a). Als ze dat zijn, doe dan niets.
-
Roep dezelfde code aan als de destructor van het linkerobject om zijn bronnen terug te geven.
-
Roep dezelfde code aan als een kopie-constructor om een diepe kopie van het rechterhandobject in het linkerobject te maken.
-
Als u dat niet kunt, verwijdert u de copy-constructor en de toewijzingsoperator zodat het programma geen kopieën van uw object kan maken.
-
-
Als u dat niet eens kunt doen omdat uw compiler de functie voor het verwijderen van constructeurs in C ++ 2011 niet ondersteunt, maakt u een constructor voor lege kopieën en een toewijzingsoperator en geeft u deze als beveiligd zodat andere klassen deze niet kunnen gebruiken.