Wilkening-Online Logo

C++ Operator-Überladung von A bis (fast) Z



Von Detlef Wilkening
todo
Version: 3

Hinweis - dieser Artikel ist noch nicht vollständig - Kapitel 3 fehlt teilweise und Kapitel 4 noch komplett. Ein Ausschnitt des Gesamt-Artikel entspricht dem Vortrag, den ich am 16.05.2012 auf dem C++ User-Treffen in Düsseldorf gehalten habe.

1. Einführung

1.1 Operator-Überladung

1.2 Die C++ Operatoren

Dieses Kapitel ist eine Übersicht über alle C++ Operatoren. Die Tabelle ist dabei nach der Priorität der Operatoren geordnet. Außerdem enthält sie noch die Informationen über die Auswertungs-Reihenfolge (L=>R oder R=>L), und ob sich der Operator überladen läßt (+) oder nicht (-) - und wenn, ob nur als Element-Funktion (EF), oder als freie Funktion und Klassen-Funktion (+, (KF)).

Prio. Operator Beschreibung Ausw. Überl.
1 :: Bereichszuordnung L=>R -
. Komponenten-Zugriff L=>R -
2 .-> Element-Zugriff, bzw. Punkt-Pfeil-Operator L=>R +
-> Element-Zugriff, bzw. Pfeil-Operator L=>R EF
[ ] Index (Array-Zugriff) L=>R EF
( ) Funktions-Aufruf L=>R EF
++ Post-Increment (n++) L=>R +
-- Post-Decrement (n--) L=>R +
typeid Typ (RTTI) L=>R -
const_cast Const-Cast L=>R -
static_cast Static-Cast L=>R -
reinterpret_cast Reinterpret-Cast L=>R -
dynamic_cast Dynamic-Cast L=>R -
3 sizeof Primäre Objekt-Größe R=>L -
++ Prä-Increment (++n) R=>L +
-- Prä-Decrement (--n) R=>L +
~ 1-er Komplement R=>L +
! Logisches Not R=>L +
+ Unäres + (Vorzeichen) R=>L +
- Unäres - (Vorzeichen) R=>L +
& Unäres & (Adresse) R=>L +
* Unäres * (Dereferenzierung) R=>L +
new, delete, new[], ... Dynamische Speicherverwaltung R=>L + (KF)
( ) Klassischer C-Cast R=>L -
4 .* Zeiger auf Element L=>R -
->* Zeiger auf Element L=>R +
5 * Multiplikation (binäres *) L=>R +
/ Division L=>R +
% Modulo L=>R +
6 + Addition (binäres +) L=>R +
- Subtraktion (binäres -) L=>R +
7 << Ausgabe bzw. Bit-Links-Schiebe L=>R +
>> Eingabe bzw. Bit-Rechts-Schiebe L=>R +
8 < Kleiner L=>R +
> Größer L=>R +
<= Kleiner-Gleich L=>R +
>= Größer-Gleich L=>R +
9 == Gleich L=>R +
!= Ungleich L=>R +
10 & Bitweises Und (binäres &) L=>R +
11 ^ Bitweises XOR L=>R +
12 | Bitweises Oder L=>R +
13 && Logisches Und L=>R +
14 || Logisches Oder L=>R +
15 ? : Bedingung R=>L -
16 = Zuweisung R=>L EF
*= Multiplikations-Zuweisung R=>L EF
/= Divisions-Zuweisung R=>L EF
%= Modulo-Zuweisung R=>L EF
+= Additions-Zuweisung R=>L EF
-= Subtraktions-Zuweisung R=>L EF
<<= Links-Bit-Schiebe-Zuweisung R=>L EF
>>= Rechts-Bit-Schiebe-Zuweisung R=>L EF
&= Bitweise-Und-Zuweisung R=>L EF
|= Bitweise-Oder-Zuweisung R=>L EF
^= Bitweise-Xor-Zuweisung R=>L EF
17 , Komma L=>R +

2. Grundlagen

2.1 Operatoren als Element-Funktionen


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   Rational mul(const Rational&) const;

   void print() const { cout << nume << '/' << deno << endl; }

private:
   int nume, deno;
};

Rational Rational::mul(const Rational& rhs) const
{
   return Rational(nume*rhs.nume, deno*rhs.deno);
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7);
   r0.print();
   r1.print();
   r2.print();

   r0 = r1.mul(r2);
   r0.print();
}


Ausgabe:

0/1
2/3
5/7
10/21


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   Rational mul(const Rational&) const;

   Rational operator*(const Rational&) const;

   void print() const { cout << nume << '/' << deno << endl; }

private:
   int nume, deno;
};

Rational Rational::mul(const Rational& rhs) const
{
   return Rational(nume*rhs.nume, deno*rhs.deno);
}

Rational Rational::operator*(const Rational& rhs) const
{
   return Rational(nume*rhs.nume, deno*rhs.deno);
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7);
   r0.print();
   r1.print();
   r2.print();

   r0 = r1.mul(r2);
   r0.print();

   r0 = r1.operator*(r2);           // Funktions-Schreibweise
   r0.print();

   r0 = r1*r2;                      // Operator-Schreibweise
   r0.print();
}


Ausgabe:

0/1
2/3
5/7
10/21
10/21
10/21

2.1.1 Vergessen Sie nicht das implizite "this"


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   // Richtig, dies ist der Operator "*" mit 2 Parametern (binärer Operator):
   // - ein impliziter Parameter ("this"), da Element-Funktion
   // - und der exlizite Parameter "rhs"
   Rational operator*(const Rational& rhs) const;

   // Compiler-Fehler - dies wäre ein Operator "*" mit 3 Parametern:
   // - ein impliziter Parameter ("this"), da Element-Funktion
   // - und zwei exlizite Parameter "lhs" und "rhs"
   // => Compiler-Fehler, da der Operator "*" keine 3 Parameter hat
   Rational operator*(const Rational& lhs, const Rational& rhs) const;

private:
   int nume, deno;
};

// Dies ist die Implementierung des Operator "*" als Element-Funktion
// Der Operator "*" hat hier 2 Parameter (binärer Operator):
// - ein impliziter Parameter ("this"), da der Operator eine Element-Funktion ist
//   Daher kann auch direkt auf die Attribute "nume" und "deno" zugegriffen werden
// - und der exlizite Parameter "rhs"
Rational Rational::operator*(const Rational& rhs) const
{
   return Rational(nume*rhs.nume, deno*rhs.deno);
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7), r3;

   // Als Element-Funktion hat der Operator "*" nur einen expliziten Parameter
   r0 = r1.operator*(r2);
   r0 = r1 * r2;

   // Compiler-Fehler - Aufruf mit 3 Parametern
   // Was soll das auch? Wozu sollte "r3" da sein?
   r0 = r1.operator*(r2, r3);
}

2.2 Operatoren als freie Funktionen


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   friend Rational mul(const Rational&, const Rational&);

   void print() const { cout << nume << '/' << deno << endl; }

private:
   int nume, deno;
};

Rational mul(const Rational& lhs, const Rational& rhs)
{
   return Rational(lhs.nume*rhs.nume, lhs.deno*rhs.deno);
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7);
   r0.print();
   r1.print();
   r2.print();

   r0 = mul(r1, r2);
   r0.print();
}


Ausgabe:

0/1
2/3
5/7
10/21


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   friend Rational mul(const Rational&, const Rational&);

   friend Rational operator*(const Rational&, const Rational&);

   void print() const { cout << nume << '/' << deno << endl; }

private:
   int nume, deno;
};

Rational mul(const Rational& lhs, const Rational& rhs)
{
   return Rational(lhs.nume*rhs.nume, lhs.deno*rhs.deno);
}

Rational operator*(const Rational& lhs, const Rational& rhs)
{
   return Rational(lhs.nume*rhs.nume, lhs.deno*rhs.deno);
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7);
   r0.print();
   r1.print();
   r2.print();

   r0 = mul(r1, r2);
   r0.print();

   r0 = operator*(r1, r2);          // Funktions-Schreibweise
   r0.print();

   r0 = r1*r2;                      // Operator-Schreibweise
   r0.print();
}


Ausgabe:

0/1
2/3
5/7
10/21
10/21
10/21

2.3 Der Vergleich zwischen beiden Varianten

2.3.1 Symmetrische Operator-Nutzung


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   Rational operator*(const Rational&) const;

   void print() const { cout << nume << '/' << deno << endl; }

private:
   int nume, deno;
};

Rational Rational::operator*(const Rational& rhs) const
{
   return Rational(nume*rhs.nume, deno*rhs.deno);
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7);
   r0.print();
   r1.print();
   r2.print();

   r0 = r1 * 4;                     // Okay => r0 = r1 * Rational(4);
   r0.print();

   r0 = 4 * r2;                     // Compiler-Fehler - geht nicht bei Element-Funktionen
   r0.print();
}


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   friend Rational operator*(const Rational&, const Rational&);

   void print() const { cout << nume << '/' << deno << endl; }

private:
   int nume, deno;
};

Rational operator*(const Rational& lhs, const Rational& rhs)
{
   return Rational(lhs.nume*rhs.nume, lhs.deno*rhs.deno);
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7);
   r0.print();
   r1.print();
   r2.print();

   r0 = r1 * 4;                     // Okay => r0 = r1 * Rational(4);
   r0.print();

   r0 = 4 * r2;                     // Okay => r0 = Rational(4) * r2;
   r0.print();
}


Ausgabe:

0/1
2/3
5/7
8/3
20/7

2.3.2 Operatoren für fremde Klassen


// So geht es leider nicht

namespace std
{
   template<...> class basic_ostream
   {
   public:
      ...
      ostream& operator<<(const Rational&);      // Sehr sehr unwahrscheinlich (siehe Text)
      ...
   };
}


#include <iostream>
using namespace std;

class Rational
{
public:
   Rational(int n=0, int d=1) : nume(n), deno(d) {}

   friend Rational operator*(const Rational&, const Rational&);

   friend ostream& operator<<(ostream&, const Rational&);

private:
   int nume, deno;
};

Rational operator*(const Rational& lhs, const Rational& rhs)
{
   return Rational(lhs.nume*rhs.nume, lhs.deno*rhs.deno);
}

ostream& operator<<(ostream& out, const Rational& arg)
{
   return out << arg.nume << '/' << arg.deno;
}

int main()
{
   Rational r0, r1(2, 3), r2(5, 7);
   cout << r0 << endl;
   cout << r1 << endl;
   cout << r2 << endl;

   r0 = r1 * r2;
   cout << r0 << endl;

   r0 = r1 * 4;
   cout << r0 << endl;

   r0 = 4 * r2;
   cout << r0 << endl;
}


Ausgabe:

0/1
2/3
5/7
10/21
8/3
20/7

2.3.3 Operatoren für Enums


#include <iostream>
using namespace std;

enum E { one, two, three };

inline ostream& operator<<(ostream& out, E e)
{
   static const char* text[] = { "eins", "zwei", "drei" };
   return out << text[e];
}

inline E& operator++(E& e)
{
   static E next[] = { two, three, one };
   return e=next[e];
}

int main()
{
   E e = one;
   cout << e << endl;           // => eins

   ++e;
   cout << e << endl;           // => zwei
   ++e;
   cout << e << endl;           // => drei
   ++e;
   cout << e << endl;           // => eins

   ++++e;
   cout << e << endl;           // => drei
}


Ausgabe:

eins
zwei
drei
eins
drei

2.3.4 Zusammenfassung

2.3.5 Zwei weitere Beispiele für freie Operator-Funktionen



#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
using namespace std;

string operator+(string s, int n)
{
   s += boost::lexical_cast<string>(n);
   return s;
}

int main()
{
   string s("abc->");
   cout << s << endl;            // abc->
   s = s + 2;
   cout << s << endl;            // abc->2
   s = s + 34;
   cout << s << endl;            // abc->234
}


Ausgabe:

abc->
abc->2
abc->234


#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
using namespace std;

string& operator<<(string& s, bool b)
{
   s += b ? "true" : "false";
   return s;
}

template<class T> string& operator<<(string& s, const T& t)
{
   s += boost::lexical_cast<string>(t);
   return s;
}

int main()
{
   string s;

   s << true << " ist: " << 1 << " + " << 2 << ' ' << "= " << 3;
   cout << s << endl;

   (s="") << 3.5 << ' ' << false;
   cout << s << endl;
}


Ausgabe:

true ist: 1 + 2 = 3
3.5 false

2.4 Sinn der funktionalen Schreibweise beim Aufruf


#include <iostream>
#include <string>
using namespace std;

class A
{
public:
   virtual string operator+(const A&) const;
};

string A::operator+(const A&) const
{
   return "A";
}

class B : public A
{
public:
   virtual string operator+(const A&) const override;
};

string B::operator+(const A& a) const
{
   string res = A::operator+(a);         // Aufruf der Basis-Klassen-Funktion geht nur so
   res += "B";
   return res;
}

int main()
{
   A a1, a2;
   string res = a1 + a2;
   cout << res << endl;

   B b;
   res = b + a2;
   cout << res << endl;
}


Ausgabe:

A
AB

2.5 Adressen von überladenen Operatoren


struct A
{
};

A operator+(const A&, const A&);

struct B
{
   B operator+(const B&) const;
};

int main()
{
   A(*plus1)(const A&, const A&) = +;               // Compiler-Fehler, so geht das nicht

   A(*plus2)(const A&, const A&) = operator+;       // Mit "operator" funktioniert es

   B(B::*plus3)(const B&) const = &B::operator+;    // Und so fuer Element-Funktionen
}

2.6 Noch eine Bemerkung zu den Parameter-Namen

3. Operator-Besonderheiten

3.1 Unäre Operatoren


#include <iostream>
using namespace std;

struct A
{
   A(int v=0) : value(v) {}

   // Element-Funktion => kein expliziter Parameter
   // Nur der implizite "this" Parameter
   bool operator!() const;

   // Als freie Funktion => natuerlich den einen expliziten Parameter
   friend A operator-(const A&);

   friend inline ostream& operator<<(ostream& out, const A& a)
   {
      return out << "A(" << a.value << ')';
   }

private:
   int value;
};

// Element-Funktion => kein expliziter Parameter
bool A::operator!() const
{
   return value==0;
}

// Als freie Funktion => natuerlich den einen expliziten Parameter
A operator-(const A& a)
{
   return A(-a.value);
}

int main()
{
   A a0;
   if (!a0)
   {
      cout << "Not a0 " << a0 << " ist true" << endl;
   }
   else
   {
      cout << "Not a0 " << a0 << " ist false" << endl;
   }

   A a1(1);
   if (!a1)
   {
      cout << "Not a1 " << a1 << " ist true" << endl;
   }
   else
   {
      cout << "Not a1 " << a1 << " ist false" << endl;
   }

   a0 = -a1;
   cout << "a0 == " << a0 << endl;
   cout << "a1 == " << a1 << endl;
}


Ausgabe:

Not a0 A(0) ist true
Not a1 A(1) ist false
a0 == A(-1)
a1 == A(1)


#include <iostream>
using namespace std;

// Klasse A - unaeres und binaeres + als Element-Funktion
struct A
{
   A& operator+();
   void operator+(const A&) const;
};

A& A::operator+()
{
   cout << "- Klasse A - unaeres +" << endl;
   return *this;
}

void A::operator+(const A&) const
{
   cout << "- Klasse A - binaeres +" << endl;
}

// Klasse B - unaeres und binaeres + als freie Funktion
struct B
{
};

B& operator+(B&);
void operator+(const B&, const B&);

B& operator+(B& b)
{
   cout << "- Klasse B - unaeres +" << endl;
   return b;
}

void operator+(const B&, const B&)
{
   cout << "- Klasse B - binaeres +" << endl;
}

int main()
{
   A a1, a2;

   cout << "+a1 =>" << endl;
   +a1;
   cout << "a1+a2 =>" << endl;
   a1+a2;
   cout << "a1 + +a2 =>" << endl;
   a1 + +a2;

   cout << endl;

   B b1, b2;

   cout << "+b1 =>" << endl;
   +b1;
   cout << "b1+b2 =>" << endl;
   b1+b2;
   cout << "b1 + +b2 =>" << endl;
   b1 + +b2;
}


Ausgabe:

+a1 =>
- Klasse A - unaeres +
a1+a2 =>
- Klasse A - binaeres +
a1 + +a2 =>
- Klasse A - unaeres +
- Klasse A - binaeres +

+b1 =>
- Klasse B - unaeres +
b1+b2 =>
- Klasse B - binaeres +
b1 + +b2 =>
- Klasse B - unaeres +
- Klasse B - binaeres +


Liste aller überladbaren unären Operatoren in C++:

Operator Siehe auch:
1-er Komplement; ~ ---
Logisches Not: ! ---
Unäres + (Vorzeichen) ---
Unäres - (Vorzeichen) ---
Unäres * (Dereferenzierung) ---
Post- bzw. Prä-Increment: n++ bzw. ++n Kapitel 3.4
Post- bzw. Prä-Decrement: n-- bzw. --n Kapitel 3.4
Unäres & (Adresse) Kapitel 3.6
Element-Zugriff: -> Kapitel 3.8
Funktions-Aufruf: () Kapitel 3.10

3.2 Zuweisungs-Operator ("=")

3.2.1 Kopier-Zuweisungs-Operator


#include <iostream>
using namespace std;

class A
{
public:
   explicit A(int arg=0) : n(arg) {}
   A& operator=(const A&);

   friend ostream& operator<<(ostream& out, const A& a)
   {
      return out <<"A(" << a.n << ')';
   }

private:
   int n;
};

A& A::operator=(const A& a)
{
   n = a.n;
   return *this;
}

int main()
{
   A a0, a1(1), a2(2);
   cout << a0 << ' ' << a1 << ' ' << a2 << endl;

   a0 = a1;

   cout << a0 << ' ' << a1 << ' ' << a2 << endl;

   a0 = a1 = a2;                                          // Mehrfach-Zuweisung

   cout << a0 << ' ' << a1 << ' ' << a2 << endl;
}


Ausgabe:

A(0) A(1) A(2)
A(1) A(1) A(2)
A(2) A(2) A(2)


// Im Prinzip der gleiche Code wie eben
// Aber nun mit "implizitem Kopier-Zuweisungs-Operator"

#include <iostream>
using namespace std;

class A
{
public:
   explicit A(int arg=0) : n(arg) {}

   // Kein expliziter Kopier-Zuweisungs-Operator mehr => impliziter

   friend ostream& operator<<(ostream& out, const A& a)
   {
      return out <<"A(" << a.n << ')';
   }

private:
   int n;
};

int main()
{
   A a0, a1(1), a2(2);
   cout << a0 << ' ' << a1 << ' ' << a2 << endl;

   a0 = a1;                                               // Funktioniert auch so

   cout << a0 << ' ' << a1 << ' ' << a2 << endl;

   a0 = a1 = a2;                                          // Funktioniert auch

   cout << a0 << ' ' << a1 << ' ' << a2 << endl;
}


Ausgabe:

A(0) A(1) A(2)
A(1) A(1) A(2)
A(2) A(2) A(2)


// Achtung - stark fehlerhafter Code
// So niemals machen

#include <cstring>
#include <iostream>
using namespace std;

class MyString
{
public:
   MyString(const char*);
   // Achtung - die impliziten Elemente sind alle fehlerhaft - so nicht machen
   // Kein expliziter Destruktor => impliziter
   // Kein expliziter Kopier-Konstruktor => impliziter
   // Kein expliziter Kopier-Zuweisungs-Operator => impliziter

   friend ostream& operator<<(ostream&, const MyString&);

private:
   char* p;
};

MyString::MyString(const char* q)
{
   p = new char[strlen(q)+1];
   strcpy(p, q);
}

ostream& operator<<(ostream& out, const MyString& str)
{
   out << str.p;
   return out;
}

int main()
{
   // Beispiel-Nutzung mit einigen Problemen...
   MyString s1("Hallo");
   cout << "s1: " << s1 << endl;

   // Fehlender korrekter Kopier-Konstruktor sorgt fuer Laufzeit-Probleme
   MyString s2(s1);
   cout << "s2: " << s2 << endl;

   // Fehlender korrekter Kopier-Zuweisungs-Operator sorgt fuer Laufzeit-Probleme
   s1 = s2;
   cout << "s1: " << s1 << endl;

   // Fehlender korrekter Destruktor sorgt fuer Speicher-Loecher
}


Ausgabe:

s1: Hallo
s2: Hallo
s1: Hallo


// Variante 1 - Kopier-Zuweisungs-Operator deklarieren, aber nicht implementieren

class A
{
private:
   // Deklaration private und ohne Implementierung, da die Klasse nicht zuweisbar sein soll
   A& operator=(const A&);
};

// Kopier-Zuweisungs-Operator von A nicht implementieren

int main()
{
   A a1, a2;
   a1 = a2;          // Compiler-Fehler, da kein Zugriff (Element private)
}                    // Bei moeglichem Zugriff (friend, ...) => Linker-Fehler



// Variante 2 - Nutzung von Boost::noncopyable

#include <boost/noncopyable.hpp>

class A : boost::noncopyable
{
};

int main()
{
   A a1, a2;
   a1 = a2;          // Compiler-Fehler
}



// Variante 3 - C++11

class A
{
public:
   A& operator=(const A&) = delete;
};

int main()
{
   A a1, a2;
   a1 = a2;          // Compiler-Fehler
}


#include <iostream>
using namespace std;

class A
{
public:
   A(int v1, int v2) : value1(v1), value2(v2) {}

   A& operator=(const A&);     // Expliziter Kopier-Zuweisungs-Operator
   A& operator=(bool);         // Weiterer anderer Zuweisungs-Operator
   A& operator=(int);          // Weiterer anderer Zuweisungs-Operator

   friend ostream& operator<<(ostream& out, const A& a)
   {
      return out << '[' << a.value1 << ',' << a.value2 << ']';
   }

private:
   int value1, value2;
};

// Expliziter Kopier-Zuweisungs-Operator
A& A::operator=(const A& a)
{
   value1 = a.value1;
   value2 = a.value2;
   return *this;
}

A& A::operator=(bool b)
{
   value1 = b;
   value2 = !b;
   return *this;
}

A& A::operator=(int v)
{
   value1 = v;
   value2 = -v;
   return *this;
}

int main()
{
   A a1(1, 11), a2(2, 22);
   cout << "a1=" << a1 << endl;
   cout << "a2=" << a2 << endl;

   a1 = a2;
   cout << "a1=" << a1 << endl;

   a1 = true;
   cout << "a1=" << a1 << endl;

   a1 = 42;
   cout << "a1=" << a1 << endl;
}


Ausgabe:

a1=[1,11]
a2=[2,22]
a1=[2,22]
a1=[1,0]
a1=[42,-42]


#include <iostream>
using namespace std;

class A
{
public:
   explicit A(int v1, int v2) : value1(v1), value2(v2) {}

   // KEIN expliziter Kopier-Zuweisungs-Operator
   A& operator=(bool);
   A& operator=(int);

   friend ostream& operator<<(ostream& out, const A& a)
   {
      return out << '[' << a.value1 << ',' << a.value2 << ']';
   }

private:
   int value1, value2;
};

A& A::operator=(bool b)
{
   value1 = b;
   value2 = !b;
   return *this;
}

A& A::operator=(int v)
{
   value1 = v;
   value2 = -v;
   return *this;
}

int main()
{
   A a1(1, 11), a2(2, 22);
   cout << "a1=" << a1 << endl;
   cout << "a2=" << a2 << endl;

   a1 = a2;                            // Impliziter Kopier-Zuweisungs-Operator
   cout << "a1=" << a1 << endl;

   a1 = true;
   cout << "a1=" << a1 << endl;

   a1 = 42;
   cout << "a1=" << a1 << endl;
}


Ausgabe:

a1=[1,11]
a2=[2,22]
a1=[2,22]
a1=[1,0]
a1=[42,-42]

3.2.2 Move-Zuweisungs-Operator


struct MyMoveableClass
{
   MyMoveableClass();
   MyMoveableClass(MyMoveableClass&&);              // Move-Konstruktor

   MyMoveableClass& operator=(MyMoveableClass&&);   // Expliziter Move-Zuweisungs-Operator

private:
   AnotherMoveableClass mMember1;
   FurtherMoveableClass mMember2;
};


MyMoveableClass& MyMoveableClass::operator=(MyMoveableClass&& arg)
{
   mMember1 = std::move(arg.mMember1);
   mMember2 = std::move(arg.mMember2);
   return *this;
}

3.3 Operative-Zuweisungs-Operatoren (z.B. "+=")


#include <iostream>
using namespace std;

struct MyInt
{
   MyInt(int v=0) : value(v) {}

   MyInt& operator+=(const MyInt&);
   MyInt operator+(const MyInt&) const;

   friend ostream& operator<<(ostream& out, const MyInt& myint)
   {
      return out << myint.value;
   }

private:
   int value;
};

// Operator "+=" auf den "Int-Werten" ausimplementiert
MyInt& MyInt::operator+=(const MyInt& arg)
{
   value += arg.value;      // Die Implementierung von "+=" basiert auf den "Int-Werten"
   return *this;
}

// Operator "+" basiert auf Operator "+="
MyInt MyInt::operator+(const MyInt& arg) const
{
   MyInt res(*this);
   res += arg;              // Die Implementierung von "+" nutzt intern "+=" von "MyInt"
   return res;
}

int main()
{
   MyInt n0, n1(1), n2(2);

   n0 = n1 + n2;
   cout << "n0 = n1 + n2  =>  n0 == " << n0 << endl;

   n0 += n2;
   cout << "n0 += n2      =>  n0 == " << n0 << endl;
}


Ausgabe:

n0 = n1 + n2  =>  n0 == 3
n0 += n2      =>  n0 == 5

3.4 Prä- und Post-Increment und Decrement Operatoren ("++" und "--")


// Achtung - die Operatoren erfuellen so noch nicht die Besonderheiten
// der Prae- und Post-Increment-Operatoren. Das folgt gleich noch.

#include <iostream>
using namespace std;

struct MyInt
{
   MyInt(int v=0) : value(v) {}

   // Bitte die Rueckgabe-Typen noch ignorieren - die bekommen wir gleich
   void operator++();                 // Ohne Dummy-Parameter => Prae-Increment, d.h. "++n"
   void operator++(int);              // Mit Dummy-Parameter => Post-Increment, d.h. "n++"

   friend ostream& operator<<(ostream& out, const MyInt& myint)
   {
      return out << myint.value;
   }

private:
   int value;
};

void MyInt::operator++()
{
   ++value;
}

void MyInt::operator++(int)
{
   ++value;
}

int main()
{
   MyInt n(2);
   cout << "n == " << n << endl;

   ++n;                                // Prae-Increment
   cout << "n == " << n << endl;

   n++;                                // Post-Increment
   cout << "n == " << n << endl;
}


Ausgabe:

n == 2
n == 3
n == 4



#include <iostream>
using namespace std;

struct MyInt
{
   MyInt(int v=0) : value(v) {}

   MyInt& operator++();                 // Prae-Increment mit Non-Const-Referenz Rueckgabe

   friend ostream& operator<<(ostream& out, const MyInt& myint)
   {
      return out << myint.value;
   }

private:
   int value;
};

MyInt& MyInt::operator++()
{
   ++value;
   return *this;
}

int main()
{
   MyInt n(2);
   cout << "n == " << n << endl;

   ++n;
   cout << "n == " << n << endl;

   ++++++n;
   cout << "n == " << n << endl;

   MyInt n2;
   n2 = ++n;
   cout << "n == " << n << endl;
   cout << "n2 == " << n2 << endl;

   cout << endl;

   int x = 11;
   cout << "x == " << x << endl;

   ++x;
   cout << "x == " << x << endl;

   ++++++x;                             // Mehrfach-Anwendung von "++n" geht auch bei "int"
   cout << "x == " << x << endl;
}


Ausgabe:

n == 2
n == 3
n == 6
n == 7
n2 == 7

x == 11
x == 12
x == 15


#include <iostream>
using namespace std;

struct MyInt
{
   MyInt(int v=0) : value(v) {}

   const MyInt operator++(int);                 // Post-Increment mit Const-Kopie Rueckgabe

   friend ostream& operator<<(ostream& out, const MyInt& myint)
   {
      return out << myint.value;
   }

private:
   int value;
};

const MyInt MyInt::operator++(int)
{
   MyInt tmp(*this);
   ++value;
   return tmp;
}

int main()
{
   MyInt n(2);
   cout << "n == " << n << endl;

   n++;
   cout << "n == " << n << endl;

   // n++++;                      // Waere Compiler-Fehler - aufgrund der "Const-Rueckgabe"

   MyInt n2;
   n2 = n++;
   cout << "n == " << n << endl;
   cout << "n2 == " << n2 << endl;

   cout << endl;

   int x = 11;
   cout << "x == " << x << endl;

   x++;
   cout << "x == " << x << endl;

   // x++++;                      // Waere Compiler-Fehler - auch bei "int"
}


Ausgabe:

n == 2
n == 3
n == 4
n2 == 3

x == 11
x == 12


#include <iostream>
#include <vector>
using namespace std;

int main()
{
   vector<int> v;
   v.push_back(11);
   v.push_back(22);
   v.push_back(33);

   // Bevorzuge Prae-Operator "++it" wenn moeglich - z.B. bei Iteratoren in Schleifen
   for (vector<int>::const_iterator it = v.begin(); it != v.end(); ++it)
   {
      cout << *it << endl;
   }
}


Ausgabe:

11
22
33

3.5 Logisches "Und" ("&&") und logisches "Oder" ("||")


#include <iostream>
using namespace std;

struct A
{
   explicit A(bool v) : value(v) {}

   bool operator&&(const A&) const;                       // Logisches Und

   friend ostream& operator<<(ostream& out, const A& a)
   {
      return out << boolalpha << a.value;
   }

private:
   bool value;
};

bool A::operator&&(const A& a) const
{
   return value && a.value;
}

A fa(bool b)
{
   cout << "fa(" << boolalpha << b << ") ";
   return A(b);
}

bool f(bool b)
{
   cout << "f(" << boolalpha << b << ") ";
   return b;
}

int main()
{
   cout << "Bool-Test" << endl;

   cout << "->  f(false) && f(false)  =>  ";
   f(false) && f(false);                               // Kurzschluss-Auswertung
   cout << endl;                                       // => nur ein Aufruf von "f(false)"

   cout << "->  f(false) && f(true)  =>  ";
   f(false) && f(true);                                // Kurzschluss-Auswertung
   cout << endl;                                       // => nur der Aufruf von "f(false)"

   cout << "->  f(true) && f(false)  =>  ";
   f(true) && f(false);
   cout << endl;

   cout << "->  f(true) && f(true)  =>  ";
   f(true) && f(true);
   cout << endl;

   cout << endl;

   cout << "A-Test" << endl;

   cout << "->  fa(false) && fa(false)  =>  ";
   fa(false) && fa(false);                             // Keine Kurzschluss-Auswertung
   cout << endl;                                       // => "fa" wird 2 x aufgerufen

   cout << "->  fa(false) && fa(true)  =>  ";
   fa(false) && fa(true);                              // Keine Kurzschluss-Auswertung
   cout << endl;                                       // => "fa" wird 2 x aufgerufen

   cout << "->  fa(true) && fa(false)  =>  ";
   fa(true) && fa(false);
   cout << endl;

   cout << "->  fa(true) && fa(true)  =>  ";
   fa(true) && fa(true);
   cout << endl;
}


Ausgabe:

Bool-Test
->  f(false) && f(false)  =>  f(false)
->  f(false) && f(true)  =>  f(false)
->  f(true) && f(false)  =>  f(true) f(false)
->  f(true) && f(true)  =>  f(true) f(true)

A-Test
->  fa(false) && fa(false)  =>  fa(false) fa(false)
->  fa(false) && fa(true)  =>  fa(true) fa(false)
->  fa(true) && fa(false)  =>  fa(false) fa(true)
->  fa(true) && fa(true)  =>  fa(true) fa(true)


type g1(), g2(), g3();

void fct()
{
   if (g1() && (g2() || g3()))
   {
      doit1();
   }
}

3.6 Adress-Operator ("&")


#include <iostream>
using namespace std;

class A
{
public:
   const void* address() const { return this; }

   const void* operator&() const { return reinterpret_cast<void*>(1); }
};

class B
{
public:
   const void* address() const { return this; }
};

const void* operator&(const B&) { return reinterpret_cast<void*>(2); }

int main()
{
   A a;
   cout << "a.address(): " << a.address() << endl;
   cout << "&a:          " << &a << endl;

   cout << endl;

   B b;
   cout << "b.address(): " << b.address() << endl;
   cout << "&b:          " << &b << endl;
}


Mögliche Ausgabe (nur "möglich" wegen Adress-Abhängigkeit):

a.address(): 0031FB97
&a:          00000001

b.address(): 0031FB8B
&b:          00000002


#include <iostream>
#include <boost/utility.hpp>
using namespace std;

class A
{
public:
   const void* address() const { return this; }

   const void* operator&() const { return reinterpret_cast<void*>(1); }
};

class B
{
public:
   const void* address() const { return this; }
};

const void* operator&(const B&) { return reinterpret_cast<void*>(2); }

int main()
{
   A a;
   cout << "addressof(a): " << boost::addressof(a) << endl;  // Oder std::addressof in C++11
   cout << "a.address():  " << a.address() << endl;
   cout << "&a:           " << &a << endl;

   cout << endl;

   B b;
   cout << "addressof(b): " << boost::addressof(b) << endl;  // Oder std::addressof in C++11
   cout << "b.address():  " << b.address() << endl;
   cout << "&b:           " << &b << endl;
}


Mögliche Ausgabe (nur "möglich" wegen Adress-Abhängigkeit):

addressof(a): 0031FB97
a.address():  0031FB97
&a:           00000001

addressof(b): 0031FB8B
b.address():  0031FB8B
&b:           00000002

3.7 Array-Zugriff bzw. Index-Operator ("[ ]")


#include <iostream>
#include <string>
using namespace std;

struct A
{
   void operator[](int) const;
   void operator[](const string&) const;
};

void A::operator[](int n) const
{
   cout << "A[" << n << ']' << endl;
}

void A::operator[](const string& s) const
{
   cout << "A[\"" << s << "\"]" << endl;
}

int main()
{
   A a;
   a[1];
   a[22];
   a[""];
   a["C++"];
}


Ausgabe:

A[1]
A[22]
A[""]
A["C++"]


#include <iostream>
using namespace std;

struct IntArray
{
   IntArray(int v0=0, int v1=0, int v2=0) : a(v0), b(v1), c(v2) {}

   int operator[](int) const;

   friend ostream& operator<<(ostream& out, const IntArray& a)
   {
      return out << "IntArray[" << a.a << ',' << a.b << ',' << a.c << ']';
   }

private:
   int a, b, c;
};

int IntArray::operator[](int idx) const
{
   switch (idx)
   {
   case 0:
      return a;
   case 1:
      return b;
   }
   return c;
}

int main()
{
   IntArray a(11, 22);
   cout << "a: " << a << endl;
   cout << "a[0]: " << a[0] << endl;
   cout << "a[1]: " << a[1] << endl;
   cout << "a[2]: " << a[2] << endl;
}


Ausgabe:

a: IntArray[11,22,0]
a[0]: 11
a[1]: 22
a[2]: 0


#include <iostream>
using namespace std;

struct IntArray
{
   IntArray(int v0=0, int v1=0, int v2=0) : a(v0), b(v1), c(v2) {}

   int operator[](int) const;

   friend ostream& operator<<(ostream& out, const IntArray& a)
   {
      return out << "IntArray[" << a.a << ',' << a.b << ',' << a.c << ']';
   }

private:
   int a, b, c;
};

int IntArray::operator[](int idx) const
{
   switch (idx)
   {
   case 0:
      return a;
   case 1:
      return b;
   }
   return c;
}

int main()
{
   IntArray a(11, 22);
   cout << "a: " << a << endl;
   cout << "a[0]: " << a[0] << endl;
   cout << "a[1]: " << a[1] << endl;
   cout << "a[2]: " << a[2] << endl;

   a[2] = 33;               // Compiler-Fehler - "rvalue" laesst sich nicht schreiben
}


#include <iostream>
using namespace std;

struct IntArray
{
   IntArray(int v0=0, int v1=0, int v2=0) : a(v0), b(v1), c(v2) {}

   int& operator[](int) /* kein "const" mehr */;

   friend ostream& operator<<(ostream& out, const IntArray& a)
   {
      return out << "IntArray[" << a.a << ',' << a.b << ',' << a.c << ']';
   }

private:
   int a, b, c;
};

int& IntArray::operator[](int idx) /* kein "const" mehr */
{
   switch (idx)
   {
   case 0:
      return a;
   case 1:
      return b;
   }
   return c;
}

int main()
{
   IntArray a(11, 22);
   cout << "a: " << a << endl;
   cout << "a[0]: " << a[0] << endl;
   cout << "a[1]: " << a[1] << endl;
   cout << "a[2]: " << a[2] << endl;

   a[2] = 33;                     // Super - funktioniert jetzt

   cout << endl;
   cout << "a: " << a << endl;
   cout << "a[0]: " << a[0] << endl;
   cout << "a[1]: " << a[1] << endl;
   cout << "a[2]: " << a[2] << endl;
}


Ausgabe:

a: IntArray[11,22,0]
a[0]: 11
a[1]: 22
a[2]: 0

a: IntArray[11,22,33]
a[0]: 11
a[1]: 22
a[2]: 33


#include <iostream>
using namespace std;

struct IntArray
{
   IntArray(int v0=0, int v1=0, int v2=0) : a(v0), b(v1), c(v2) {}

   int& operator[](int);

   friend ostream& operator<<(ostream& out, const IntArray& a)
   {
      return out << "IntArray[" << a.a << ',' << a.b << ',' << a.c << ']';
   }

private:
   int a, b, c;
};

int& IntArray::operator[](int idx)
{
   switch (idx)
   {
   case 0:
      return a;
   case 1:
      return b;
   }
   return c;
}

int main()
{
   IntArray a(11, 22);
   a[2] = 33;

   cout << "a: " << a << endl;
   cout << "a[0]: " << a[0] << endl;
   cout << "a[1]: " << a[1] << endl;
   cout << "a[2]: " << a[2] << endl;

   cout << endl;

   const IntArray ca(111, 222, 333);

   cout << "ca: " << ca << endl;
   cout << "ca[0]: " << ca[0] << endl;      // Compiler-Fehler - Operator [] ist "non-const"
   cout << "ca[1]: " << ca[1] << endl;      // Compiler-Fehler - Operator [] ist "non-const"
   cout << "ca[2]: " << ca[2] << endl;      // Compiler-Fehler - Operator [] ist "non-const"
}


#include <iostream>
using namespace std;

struct IntArray
{
   IntArray(int v0=0, int v1=0, int v2=0) : a(v0), b(v1), c(v2) {}

   int& operator[](int);
   int operator[](int) const;

   friend ostream& operator<<(ostream& out, const IntArray& a)
   {
      return out << "IntArray[" << a.a << ',' << a.b << ',' << a.c << ']';
   }

private:
   int a, b, c;
};

int& IntArray::operator[](int idx)
{
   switch (idx)
   {
   case 0:
      return a;
   case 1:
      return b;
   }
   return c;
}

int IntArray::operator[](int idx) const
{
   switch (idx)
   {
   case 0:
      return a;
   case 1:
      return b;
   }
   return c;
}

int main()
{
   IntArray a(11, 22);
   a[2] = 33;

   cout << "a: " << a << endl;
   cout << "a[0]: " << a[0] << endl;
   cout << "a[1]: " << a[1] << endl;
   cout << "a[2]: " << a[2] << endl;

   cout << endl;

   const IntArray ca(111, 222, 333);

   cout << "ca: " << ca << endl;
   cout << "ca[0]: " << ca[0] << endl;
   cout << "ca[1]: " << ca[1] << endl;
   cout << "ca[2]: " << ca[2] << endl;
}


Ausgabe:

a: IntArray[11,22,33]
a[0]: 11
a[1]: 22
a[2]: 33

ca: IntArray[111,222,333]
ca[0]: 111
ca[1]: 222
ca[2]: 333

3.8 Element-Zugriff bzw. Pfeil-Operator ("->")


int main()
{
   shared_ptr<string> ps(new string("Hallo Welt");
   cout << ps->length() << endl;                   // Nutzung des ueberladenen -> Operators
}


// Eine Klasse "A", mit einem freien Operator "+" - irgendwie implementiert
// Und Benutzung von unserem Operator "+"

class A {};
A operator+(const A&, const A&);

A a1, a2;
A a = a1 + a2;


struct sss
{
   int n;
};

sss s = { 1 };   // Ein Objekt "s" der Struktur "sss" erzeugen
sss* p = &s;     // Einen Zeiger "p" darauf besorgen und initialisieren
cout << p->n;    // Ausgabe des Members "n" ueber den Zeiger "p" mit "->"


struct A
{
   int n;
};

struct APtr
{
   APtr(A* arg) : p(arg) {}
   A* operator->() { return p; }
   A* p;
};

int main()
{
   A a = { 2 };
   APtr pa(&a);
   cout << pa->n;
}


#include <iostream>
using namespace std;

struct B
{
   int operator->() { return 5; }      // Rueckgabe eines "int"
};

int main()
{
    B b;
    int x = b.operator->();            // Aufruf in "funktionaler" Schreibweise
    cout << x << endl;
}


Ausgabe:

5


#include <iostream>
using namespace std;

struct A;
struct AProxy;

struct AProxyProxy
{
   AProxyProxy(A* p) : pa(p) {}

   A* operator->() { return pa; }                       // Proxy-Proxy gibt A zurueck

   A* pa;
};

struct AProxy
{
   AProxy(A* p) : pa(p) {}

   AProxyProxy operator->() { return AProxyProxy(pa); } // Proxy gibt ein Proxy-Proxy zurueck

   A* pa;
};

struct A
{
   A(int x) : n(x) {}

   AProxy operator->() { return AProxy(this); }         // A gibt nur ein Proxy zurueck

   int n;
};


int main()
{
    A a(6);
    cout << a->n << endl;
}


Ausgabe:

6

3.9 Zeiger-Auf-Element-Zugriff bzw. Pfeil-Stern-Operator ("->*")


#include <iostream>
using namespace std;

struct A
{
   int n;
   int m;
   void f() { cout << "A::f()" << endl; }
   void g() { cout << "A::g()" << endl; }
};

int main()
{
   int A::*a_int = &A::n;
   void (A::*a_fct)() = &A::f;

   A a = { 3, 4 };
   A* pa = &a;

   cout << a.*a_int << endl;                            // => 3
   cout << pa->*a_int << endl;                          // => 3

   (a.*a_fct)();                                        // => A::f()
   (pa->*a_fct)();                                      // => A::f()

   cout << endl;

   a_int = &A::m;
   a_fct = &A::g;

   cout << a.*a_int << endl;                            // => 4
   cout << pa->*a_int << endl;                          // => 4

   (a.*a_fct)();                                        // => A::g()
   (pa->*a_fct)();                                      // => A::g()

   cout << endl;

   A a2 = { 5, 6 };
   A* pa2 = &a2;

   cout << a2.*a_int << endl;                            // => 6
   cout << pa2->*a_int << endl;                          // => 6
}


Ausgabe:

3
3
A::f()
A::f()

4
4
A::g()
A::g()

6
6


#include <iostream>
using namespace std;

struct A
{
   int x;

   void operator->*(int n) { cout << "A::->*(" << n << ')' << endl; }

   void operator->*(int A::* a) { cout << "A::->*(int A::*) : " << this->*a << endl; }
};

void operator->*(A, bool b)
{
   cout << "->*(A, " << b << ')' << endl;
}

int main()
{
   cout << boolalpha;

   A a = { 4 };

   a->*(6);
   a->*(true);

   int A::*ax = &A::x;
   a->*ax;
}


Ausgabe:

A::->*(6)
->*(A, true)
A::->*(int A::*) : 4


#include <iostream>
#include <boost/noncopyable.hpp>
using namespace std;

struct A
{
   A(int a, int b) : x(a), y(b) {}

   int x;
   int y;

   void fct() { cout << "A::fct(): " << x << ',' << y << endl; }
};

struct APtr : boost::noncopyable
{
   APtr(A* pa) : p(pa) {}
   ~APtr() { delete p; }

   A& operator*() { return *p; }
   A* operator->() { return p; }

   template<class T> T& operator->*(T A::*idx) { return p->*idx; }

   A* p;
};


int main()
{
   APtr pa = new A(4, 5);
   pa->fct();                          // Normaler Pfeil-Operator "->"
   (*pa).fct();                        // Normaler Dereferenzierungs-Operator "*"

   int A::*a_int = &A::x;
   cout << pa->*a_int << endl;         // Nutzung des ueberladenen Operators "->*"
   cout << (*pa).*a_int << endl;       // Simulation von Operator "->*" mit ".*" - s.u.

   a_int = &A::y;
   cout << pa->*a_int << endl;         // Nutzung des ueberladenen Operators "->*"
   cout << (*pa).*a_int << endl;       // Simulation von Operator "->*" mit ".*" - s.u.
}


Ausgabe:

A::fct(): 4,5
A::fct(): 4,5
4
4
5
5

3.10 Funktions-Aufruf-Operatoren ("( )")


#include <iostream>
using namespace std;

class A
{
public:
   void operator()() const;
};

void A::operator()() const
{
   cout << "Funktions-Aufruf-Operator ()" << endl;
}

int main()
{
   A a;
   a();          // Keine Funktion - Aufruf des Operators "()" fuer das Objekt "a"
}


Ausgabe:

Funktions-Aufruf-Operator ()


#include <iostream>
using namespace std;

class A
{
public:
   void operator()() const;
   void operator()(int) const;
   void operator()(bool) const;
   void operator()(double, int=5) const;
};

void A::operator()() const
{
   cout << "Funktions-Aufruf-Operator ()" << endl;
}

void A::operator()(int n) const
{
   cout << "Funktions-Aufruf-Operator (int " << n << ")" << endl;
}

void A::operator()(bool b) const
{
   cout << "Funktions-Aufruf-Operator (bool " << b << ")" << endl;
}

void A::operator()(double d, int n) const
{
   cout << "Funktions-Aufruf-Operator (double " << d << ", int " << n << ")" << endl;
}

int main()
{
   A a;
   a();               // Aufruf des Operators "()"
   a(4);              // Aufruf des Operators "(int)" mit "4"
   a(true);           // Aufruf des Operators "(bool)" mit "true"
   a(2.72);           // Aufruf des Operators "(double, int)" mit "2.72, 5"
   a(3.14, 6);        // Aufruf des Operators "(double, int)" mit "3.14, 6"
}


Ausgabe:

Funktions-Aufruf-Operator ()
Funktions-Aufruf-Operator (int 4)
Funktions-Aufruf-Operator (bool 1)
Funktions-Aufruf-Operator (double 2.72, int 5)
Funktions-Aufruf-Operator (double 3.14, int 6)


struct MyLess
{
   bool operator()(int larg, int rarg) { return larg<rarg; }
};

int main()
{
   vector<int> v;

   sort(begin(v), end(v), MyLess());
}

3.11 Konvertierungs-Operatoren

todo

3.12 User-definierte Literale - Operator ("""")

todo

4. Boost.Operator

todo

4.1 Einführung

todo

4.2 Operator-Konzepte

todo

4.3 Composite-Konzepte

todo

4.4 Fazit

todo

5. Fazit

5.1 Was fehlte?

5.2 Wichtig für C++

5.3 Fazit

6. Links

Hier die Links zu den speziellen Themen aus diesem Artikel:
  1. Die Boost Web-Seite im Internet:

  2. Ein Einführungs-Artikel in Boost von mir:

  3. Mein Artikel zum Thema "override in C++11":

  4. Mein Artikel zur "Regel der 3":
    • Noch nicht veröffentlicht

  5. Die "Regel der 3" finden Sie auch gut erklärt im folgenden Buch:
    • Scott Meyers, Effektiv C++ programmieren
    • 3.Auflage, Item 11
    • Addison-Wesley, ISBN 9-783827-31305-8

  6. Mein Artikel zu RAII ("resource aquisition is initialisation"):
    • Noch nicht veröffentlicht

  7. Mein Artikel zu den "Parameter-Übergabe-Konventionen":
    • Noch nicht veröffentlicht

  8. Vergleiche das Kapitel 2.4 über "Kopien und temporäre Objekte" in meinem Artikel:

  9. ISO C++ 11 Standard von 2011: ISO/IEC 14882:2011(E)

  10. Mein Artikel zum Thema "Überladen mit const":

  11. ISO C++ 11 Standard von 2011: ISO/IEC 14882:2011(E)

7. Literatur

C++ Bücher, die sich nur oder zumindest zu einem großen Teil mit Operator-Überladung beschäftigen, kenne ich nicht. Natürlich enthält wohl jedes Lehrbuch zu C++ auch ein Kapitel zur Operator-Überladung - unterm Strich wird sie aber im Verhältnis zu anderen Themen doch immer recht kurz behandelt - daher ja auch dieser Artikel.

Trotzdem haben es 2 Bücher in die Literatur-Liste zur C++ Operator-Überladung geschafft. Genauso wie bei den Büchern ist auch bei Web-Seiten das Thema "Operator-Überladung in C++" stark unterrepräsentiert - man gut, daß ich nun diesen Artikel geschrieben habe. Aber ein paar Artikel kann ich Ihnen doch nennen:

8. Versions-Historie

Die Versions-Historie dieses Artikels:
Schlagwörter: