Wenn Sie diese vier Methoden (sechs in C++11) nicht definieren, erzeugt der Compiler sie für Sie:
- Standard-Konstruktor
- Konstruktor kopieren
- Zuweisung Operator
- Zerstörer
- Move-Konstruktor (C++11)
- Zuweisung verschieben (C++11)
Wenn Sie wissen wollen, warum?
Damit soll die Abwärtskompatibilität mit C gewahrt werden (da C-Strukturen mit = und in der Deklaration kopierbar sind). Aber es macht auch das Schreiben einfacher Klassen einfacher. Einige würden argumentieren, dass es wegen des "shallow copy problem" zu Problemen führt. Mein Argument dagegen ist, dass man keine Klasse mit eigenen RAW-Zeigern in ihr haben sollte. Durch die Verwendung geeigneter Smart Pointer wird dieses Problem beseitigt.
Standard-Konstruktor (wenn keine anderen Konstruktoren definiert sind)
Der vom Compiler erzeugte Standardkonstruktor ruft den Standardkonstruktor der Basisklasse und dann den Standardkonstruktor jedes Mitglieds auf (in der Reihenfolge, in der sie deklariert sind)
Destruktor (wenn kein Destruktor definiert ist)
Ruft den Destruktor der einzelnen Mitglieder in umgekehrter Reihenfolge der Deklaration auf. Ruft dann den Destruktor der Basisklasse auf.
Kopierkonstruktor (wenn kein Kopierkonstruktor definiert ist)
Ruft den Kopierkonstruktor der Basisklasse auf und übergibt das src-Objekt. Ruft dann den Kopierkonstruktor jedes Mitglieds auf und verwendet dabei die Mitglieder des src-Objekts als den zu kopierenden Wert.
Zuweisung Operator
Ruft den Zuweisungsoperator der Basisklasse auf und übergibt das src-Objekt. Ruft dann den Zuweisungsoperator für jedes Mitglied auf und verwendet das src-Objekt als den zu kopierenden Wert.
Move-Konstruktor (wenn kein Move-Konstruktor definiert ist)
Ruft den Move-Konstruktor der Basisklasse auf und übergibt das src-Objekt. Ruft dann den move-Konstruktor jedes Mitglieds auf und verwendet die Mitglieder des src-Objekts als den zu verschiebenden Wert.
Zuweisungsoperator verschieben
Ruft den Zuweisungsoperator der Basisklasse move auf und übergibt das Objekt src. Ruft dann den Zuweisungsoperator für jedes Mitglied auf und verwendet dabei das src-Objekt als den zu kopierenden Wert.
Wenn Sie eine Klasse wie diese definieren:
struct some_struct: public some_base
{
std::string str1;
int a;
float b;
char* c;
std::string str2;
};
Was der Compiler erstellt, ist:
struct some_struct: public some_base
{
std::string str1;
int a;
float b;
char* c;
std::string str2;
// Conceptually two different versions of the default constructor are built
// One is for value-initialization the other for zero-initialization
// The one used depends on how the object is declared.
// some_struct* a = new some_struct; // value-initialized
// some_struct* b = new some_struct(); // zero-initialized
// some_struct c; // value-initialized
// some_struct d = some_struct(); // zero-initialized
// Note: Just because there are conceptually two constructors does not mean
// there are actually two built.
// value-initialize version
some_struct()
: some_base() // value-initialize base (if compiler generated)
, str1() // has a normal constructor so just call it
// PODS not initialized
, str2()
{}
// zero-initialize version
some_struct()
: some_base() // zero-initialize base (if compiler generated)
, str1() // has a normal constructor so just call it.
, a(0)
, b(0)
, c(0) // 0 is NULL
, str2()
// Initialize all padding to zero
{}
some_struct(some_struct const& copy)
: some_base(copy)
, str1(copy.str1)
, a(copy.a)
, b(copy.b)
, c(copy.c)
, str2(copy.str2)
{}
some_struct& operator=(some_struct const& copy)
{
some_base::operator=(copy);
str1 = copy.str1;
a = copy.a;
b = copy.b;
c = copy.c;
str2 = copy.str2;
return *this;
}
~some_struct()
{}
// Note the below is pseudo code
// Also note member destruction happens after user code.
// In the compiler generated version the user code is empty
: ~str2()
// PODs don't have destructor
, ~str1()
, ~some_base();
// End of destructor here.
// In C++11 we also have Move constructor and move assignment.
some_struct(some_struct&& copy)
// ^^^^ Notice the double &&
: some_base(std::move(copy))
, str1(std::move(copy.str1))
, a(std::move(copy.a))
, b(std::move(copy.b))
, c(std::move(copy.c))
, str2(std::move(copy.str2))
{}
some_struct& operator=(some_struct&& copy)
// ^^^^ Notice the double &&
{
some_base::operator=(std::move(copy));
str1 = std::move(copy.str1);
a = std::move(copy.a);
b = std::move(copy.b);
c = std::move(copy.c);
str2 = std::move(copy.str2);
return *this;
}
};