2017-06-21 2 views
-4

Ich bin ziemlich neu zu dem Thema Vorlagen in C++. Warum müssen wir im folgenden Spielzeug-Beispielcode dem Namen der Klasse und jeder Funktion vorangehen mit template <class T> (was bedeutet, warum brauchen wir sie überhaupt)?Verwendung der Vorlage <class T> in C++ beim Deklarieren von Klassen und Funktionen

Ist es möglich, den Code zu ändern, um überall template <class T> zu verwenden?

#include <iostream> 
#include <vector> 
#include <cstdlib> 
#include <string> 
#include <stdexcept> 

using namespace std; 

template <class T> 
class Stack { private: 
    vector<T> elements; 

    public: 
    void push(T const &); 
    void pop(); 
    T top(); 
    bool empty(); }; 

template <class T> 
void Stack<T>::push(T const &elem) { 
    elements.push_back(elem); } 

template <class T> 
void Stack<T>::pop() { 
    if (elements.empty()) { 
     throw out_of_range("Stack<>::pop(): empty stack"); 
    } else { 
     elements.pop_back(); 
    } 
} 

template <class T> 
T Stack<T>::top() { 
    if (empty()) { 
     throw out_of_range("Stack<>::top(): empty stack"); 
    } 
    return elements.back(); 
} 

template <class T> 
bool Stack<T>::empty() { 
    return elements.empty(); 
} 


int main() { 
    try { 
     Stack<int> intStack;  // Stack of ints 
     Stack<string> stringStack; // Stack of strings 

     // Manipulate integer stack 
     intStack.push(7); 
     cout << intStack.top() << endl; 

     // Manipulate string stack 
     stringStack.push("hello"); 
     cout << stringStack.top() << std::endl; 
     stringStack.pop(); 
     stringStack.pop(); 
    } 
    catch (exception const &ex) { 
     cerr << "Exception: " << ex.what() << endl; 
     return -1; 
    } 
} 
+5

Was ist "Vorlagenkopf"? – teivaz

+0

Es gibt keine Header für die Vorlage. Wenn Sie keine Vorlage verwenden möchten, definieren Sie die Klasse "define two" für zwei verschiedene Datentypen "std :: string" und "int". – P0W

+0

Mit "Template Header" meine ich "Vorlage ". Wie soll ich es dann nennen? Ich sagte, ich bin neu in dem Thema. Bitte sei verständlicher. – cerebrou

Antwort

4

Sie haben template <class T> in jedem Mitglieds Definition enthalten, weil dieser Teil des Namens des Elements ist.

Sie können die Funktionen in der Klasse-Schablonenkörper definieren, für nur eine Zeile mit template <class T>

template <class T> 
class Stack { 
    private: 
    vector<T> elements; 

    public: 
    void push(T const &) { 
     elements.push_back(elem); } 
    void pop() { 
     if (elements.empty()) { 
      throw out_of_range("Stack<>::pop(): empty stack"); 
     } else { 
      elements.pop_back(); 
     } } 
    T top() { 
     if (empty()) { 
      throw out_of_range("Stack<>::top(): empty stack"); 
     } 
     return elements.back(); } 
    bool empty() { 
     return elements.empty(); } }; 
2

C++ ist eine statically typed Sprache.

Da dies der Fall ist, sagen wir, ich wollte eine Funktion, um das Minimum oder Maximum von zwei Werten zu überprüfen.

Ich könnte eine Funktion wie folgt erstellen:

int max(int a, int b) { return (a > b) ? a : b; } 

Das funktioniert aber nur für int Typen. Wenn ich einen wollen eine für double oder uint64_t oder FooBarClass, würde ich zusätzliche Funktionen erstellen müssen:

double max(double a, double b) { return (a > b) ? a : b; } 
uint64_t max(uint64_t a, uint64_t b) { return (a > b) ? a : b; } 
FooBarClass max(FooBarClass a, FooBarClass b) { return (a > b) ? a : b; } 

Warum in der folgenden Spielzeug Beispielcode müssen wir die Klasse und Funktion jeder einzelnen Namen mit Vorlage vorangehen?

In C++, eine template ist ein Weg, ein Konzept als "generics" bekannt einzuführen. Bei Generika müssen Sie sich nicht mehr mit dem Erstellen einer Funktion für jeden Typ befassen, der Typ wird aus der Signatur der Template-Funktion abgeleitet.

Anstatt also könnte ich schreibe folgendes:

template < typename T > // the typename or class keywords are synonymous when declaring a template 
T max(T a, T b) { return (a > b) ? a : b; } 

Die Einbeziehung von template < typename T > auf die Funktionssignatur an den Compiler zeigt, dass diese Funktion nur eine „generische“ Funktion und muss entsprechend verarbeitet werden.

Wenn auf der anderen Seite, Sie hatten gerade folgende:

T max(T a, T b) { return (a > b) ? a : b; } 

Der Compiler wird T erwartet ein expliziter Typ (wie typedef int T;) zu sein.

können eine Vorlage auf eine Klasse oder Funktion angewendet werden, und beide zugleich:

template < typename T > 
class Wrapper { 
    public: 
     Wrapper(const T& val) : _val(val) {} 
     // ... other code 

     template < typename X > 
     operator X() 
     { 
      return static_cast<X>(this->_val); 
     } 

     T operator+(const T& val) 
     { 
      return this->_val + val; 
     } 

     friend std::ostream& operator<<(std::ostream& os, const Wrapper& val) 
     { 
      os << val._val; 
      return os; 
     } 

    private: 
     T _val; 
}; 

int main(int argc, char* argv[]) 
{ 
    Wrapper<int> x(42); 
    // template deduction will call Wrapper::operator X() with X being a double 
    double d = x; 
    // template deduction will call Wrapper::operator X() with X being a long 
    long l = x; 
    // this actually calls T operator+(const T& val) with val = 10 and T = int 
    int i = x + 10; 

    std::cout << "x = " << x << std::endl // 42 
       << "d = " << d << std::endl // 42 
       << "l = " << l << std::endl // 42 
       << "i = " << i << std::endl; // 52 
    return 0; 
} 

Sie können einen Vorlagentyp auch explizit festlegen, wird dies als template specialization bekannt und ist über den Rahmen Diese Antwort wurde gegeben, wenn Sie die aktuellen Vorlagen kennen.

Ist es möglich, den Code zu ändern, um Vorlagen nicht überall zu verwenden?

Ja und nein. Ja, Sie können die Signaturdefinition template < class T > entfernen, aber wie erwähnt, hat die Signatur der Klasse/Funktion eine ganz andere Bedeutung.

Hoffe, dass ein wenig aufräumt. Vorlagen sind, wenn sie richtig verwendet werden, ein sehr mächtiges Werkzeug in C++.

+0

C++ ist * statisch typisiert *, nicht * "stark typisiert" *. Es ermöglicht implizite Konvertierungen, die verlustbehaftet sein können. – IInspectable

Verwandte Themen