robert filatow logo
Das Programmierleben leichter machen mit Templates in C++

Das Programmierleben leichter machen mit Templates in C++

Ziel

Parametisierung von Datentypen in Funktionen, wodurch man sich das Schreiben von Funktionen erleichtern kann, da man nicht für verschiedene Datentypen verschiedene Funktionen schreiben muss.

Du solltest wissen

  • Was Klassen und Objekte sind.
  • Welche grundlegenden Datentypen es gibt(int, float usw.)
  • Wie Referenzen funktionieren
  • Wie Initialisierungslisten funktionieren
  • Was der Unterschied zwischen einem Vogel ist

Das Problem mit den Datentypen

Nehmen wir an, du möchstest eine Funktion zum Addieren von Zahlen schreiben.
Dann könnte diese Funktion so aussehen:

#include <iostream>
using namespace std;
int addiere(int a, int b){
   return (a + b);
}
int main(){
  cout << addiere(42, 420) << endl;
}

462

Soweit so gut, unsere Funktion funktioniert. Aber was wenn ich nun zwei Fließkommazahlen übergebe und mir als Ergebnis ebenfalls eine Fließkommazahl wünsche?

#include <iostream>
using namespace std;
int addiere(int a, int b){
   return (a + b);
}
int main(){
  cout << addiere(42.2, 42.0) << endl;
}

84

Unser Ergebnis ist 84. Denn unsere Funktion gibt eine Ganzzahl zurück, irgendwo in der Funktion wird also eine Typumwandlung durchgeführt. Aber wir wollen jetzt unbedingt ganz Dolle eine Fließkommazahl und keine Ganzzahl.

1. (schlechte) Lösung:

Wir wissen noch nichts von Templates also denken wir

Hey! Ich schreibe einfach noch eine Funktion speziell für float. Easy.

– Armer Unwissender Narr
#include <iostream>
using namespace std;
int addiereGanzzahl(int a, int b){
   return (a + b);
}
float addiereFloat(float a, float b){
   return (a + b);
}
int main(){
    cout << addiereGanzzahl(42, 420) << endl;
    cout << addiereFloat(42.2, 42.0) << endl;
}

462
84.2

Problem gelöst? Aber was ist mit all den anderen Datentypen die noch eine Rolle spielen könnten?

Da wir Entwickler aber grundsätzlich faul sind, oder sein sollten, hat sich ein Bigbrain bei der Entwicklung von C++ gedacht:

Wieso nicht einfach den Datentypen parametisieren, sodass der Compiler bei Bedarf eine Funktion mit dem passenden Datentyp einsetzt?

– Bigbrain

2. Lösung mit Funktions-Templates:

Die Syntax zum definieren eines Templates lautet:

template <class identifier> function_declaration;
template <typename identifier> function_declaration;

Es gibt also zwei Möglichkeiten eine Funktions-Template zu definieren. Einmal mit dem Schlüsselwort class und einmal mit typename. Die Funktionsweise ist jedoch identisch und beides kann verwendet werden. Ich benutze im folgenden die Version mit typename:

template <typename identifier> function_declaration;

Weil ich class in diesem Kontext irgendwie etwas irritierender finde.
Unsere Beispielfunktion würde als Funktions-Template wie folgt aussehen:

#include <iostream>
using namespace std;
template <typename Typ>
Typ addiere(Typ a, Typ b){
   return (a + b);
}
int main(){
    cout << addiere(42.2, 42.0) << endl;
}

462
84.2

Nun erhalten wir sowohl unsere Ganzzahl als auch unsere Fließkommazahl mit nur einer Funktion.
Was hier passiert, ist dass der Compiler an der passenden Stelle die passende Funktion erzeugt:

cout << addiere(42, 420) << endl;      // Der Compiler erzeugt int addiere(int, int)
cout << addiere(42.2, 42.0) << endl;   // Der Compiler erzeugt float addiere(float, float)

Achtung! Templates funktionieren nur, wenn die übergebenen Argumente alle den gleichen Datentyp haben.

Was nicht geht ist folgendes:

 cout << addiere(42.2, 42) << endl;   // führt zu einem Fehler

error: no matching function for call to ‘addiere(double, int)’

Um dieses Problem zu lösen können wir einen zweiten Typ einführen:

#include <iostream>
using namespace std;
template <typename Typ, typename AndererTyp>
Typ addiere(Typ a, AndererTyp b){
   return (a + b);
}
int main(){
    cout << addiere(42.2, 42) << endl;   
    //  funktioniert nun, das Ergebnis wird als float ausgegeben da Rückgabewert: Typ
}

Nun läuft die Funktion, obwohl wir zwei verschiedene Datentypen übergeben.

Funktions-Template für Klassen

Funktions-Templates können auch Klassen als Datentyp annehmen. Natürlich muss gewährleistet werden, dass die Funktionen mit den jeweiligen Klassen auch umgehen kann.

Aus diesem Grund verwende ich in diesem Beispiel eine andere Funktion und zwar eine zum Tauschen von zwei Variablen.

#include <iostream>
using namespace std;
class Person {
    public: //public weil ich im Beispiel Getter und Setter sparen will
        char * name; 
        Person(char * name): name(name){} //Konstruktor initialisiert den Namen über Initialisierungsliste name(name)
        void printPerson(){
            std::cout << "Mein Name ist: "<< name << std::endl;
        }
};
template <typename Typ>
void tauschen(Typ &a, Typ &b){
    Typ speicher = a;
    a = b;
    b = speicher;
}
int main(){
    Person batman("Bruce Wayne");
    Person spiderman("Peter Parker");
    batman.printPerson();        // Console: "Mein Name ist: Bruce Wayne"
    spiderman.printPerson();     // Console: "Mein Name ist: Peter Parker"
    tauschen(batman, spiderman);  //tauschen Funktion wird aufgerufen, Compiler erzeugt tauschen(Person, Person)
    batman.printPerson();         //Console: "Mein Name ist: Peter Parker"
    spiderman.printPerson();     // Console: "Mein Name ist: Bruce Wayne"
}

Mein Name ist: Bruce Wayne
Mein Name ist: Peter Parker
Mein Name ist: Peter Parker
Mein Name ist: Bruce Wayne

Diese Funktion läuft nur solange, wir Variablen erhalten die auch einander zugewiesen werden können. Würden wir also zwei Objekte übergeben, bei denen eine Zuweisung gar nicht erst möglich ist, würden wir Probleme bekommen. Abhilfe könnten dann überladene Operatoren(z.b ein überladener Zuweisungsoperator) schaffen.

Zusammenfassung

  • Ein Funktions-Template ist also keine konkrete Funktionsdefinition, sondern eine Vorlage, die dem Compiler dabei hilft bei Bedarf eine Funktion für einen konkreten Datentyp zu erzeugen.
  • template <class identifier> function_declaration;
    und
    template <typename identifier> function_declaration;
    gehen beide.
  • Wenn man zwei verschiedene Datentypen als Parameter verarbeiten möchte muss man zwei Typen definieren:
    template <typename Typ, typename AndererTyp>

Hat dir der Inhalt gefallen?

Falls du mehr zu Themen der Informatik lesen willst, kannst du die Suche dafür verwenden:


Du bist der Meinung, das war der Beste Beitrag zum Thema Informatik den du jemals gelesen hast? Dann ist die einzig logische Schlussfolgerung, diesen Beitrag mit deinen Kommilitonen zu teilen. Oder auch nicht mach was du willst, ich bin nicht dein Dad.

TAGS

© 2023. All rights reserved. Website made by Robert Filatow