Stel je voor deze klasse:
class Entity {
public:
int x, y;
Entity() : x(0), y(0) { }
Entity(int x, int y) : x(x), y(y) { }
}
en hier zijn meerdere manieren om de klas te initialiseren met wat ik denk dat ik weet:
Entity ent1; //Uses the default constructor, so x=0 and y=0
Entity ent2(); //Uses the default constructor, so x=0 and y=0 (Not sure)
Entity ent3(1, 2); //Made constructor, so x=1 and y=2
Entity ent4 = Entity(); //Default constructor, so x=0 and y=0
Entity ent5 = Entity(2, 3); //Made constructor, so x=2 and y=3
Ik weet dat het mogelijk is om een object op het heapgeheugen te maken, maar dat is niet wat ik op zoek ben op dit moment.
Mijn vraag is, wat is het verschil tussen deze manieren om een object initialiseren?
Ik weet niet zeker welke ik moet gebruiken wanneer.
Antwoord 1, Autoriteit 100%
Entity ent1;
De bovenstaande verklaring gebruikt standaardconstructeur van de klasse Entity
.
Entity ent2();
De bovenstaande verklaring wordt door de compiler behandeld als een functie-prototype als dat mogelijk is. Het staat bekend als een geval van meest vexing parse (MVP) en het bestaan ervan leidde tot het uiterlijk van misleidende “slimme domme regel”: “Gebruik nooit haakjes”.
In de verklaring zoals deze wordt een door de gebruiker gedefinieerde constructeur ingeroepen voor ent3
:
Entity ent3(1, 2);
Een ander geval waarin MVP kan toeslaan is zoiets als dit:
Entity ent3_1(int(a), int(b)); // It's not what it looks like.
ent3_1
hierboven is geen variabele. De instructie declareert een functie met twee int-parameters. int(a)
is hetzelfde als int a
en is een erfenis van C-taal en declaratiesyntaxis daar.
Entity ent4 = Entity();
ent4
is een juisteversie van ent2
case tot C++11. Standaardconstructor wordt aangeroepen als onderdeel van waarde-initialisatie. Zijn vorm maakt het mogelijk om een ambiguïteitsoplossingsprincipe te vermijden dat ent2
en ent3_1
onjuist maakt. Gelijkteken hier is geen toewijzing, want hier zal geen operator=
aanroep plaatsvinden. Het maakt deel uit van de declaratiesyntaxis die bedoeld is om de initialisatie-expressie te markeren.
Entity ent5 = Entity(2, 3);
ent5
is een versie van ent3 case. Door de gebruiker gedefinieerde constructor aangeroepen als onderdeel van waarde-initialisatie.
Uw vraag is getagd als C++11 en C++11 staat uniforme initialisatiesyntaxis toe:
Entity ent12{}; // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {}; // Not an assignment
Entity ent15 = Entity{2, 3}; // Not an assignment either!
Houd er rekening mee dat uniforme initialisatiesyntaxis een voorbehoud heeft. bijv. deze regel
std::vector<int> v(10);
declareert een vector van 10 elementen. Maar deze
std::vector<int> v{10};
declareert een vector die is geïnitialiseerd met een enkel element van het type int met waarde 10. Dit gebeurt omdat std::vector
een constructor heeft met de volgende handtekening gedefinieerd:
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
In het geval dat u geen van beide () kunt gebruiken zonder MVP of {} te activeren zonder een ongewenste constructor aan te roepen, maakt de syntaxis van de waarde-initialisatietoewijzing het mogelijk om het probleem op te lossen.
Addendum: Moet CppCon 2018: Nicolai Josuttis “The Nightmare of Initialization in C++”