2017-01-12 6 views
0

Ich versuche, eine C++ Template Klasse zu entwerfen, die alle Features eines Tree (d. H. appendChild, childCount) enthalten wird. Ich möchte dann extend aus dieser Vorlage Klasse und benutzerdefinierte Tree-Klasse mit vorhandenen Funktionen (lesen Sie als Methods) sowie zusätzliche Funktionen.Vererbung auf C++ - Vorlagenklasse

Bis jetzt habe ich das.

#include <iostream> 
#include <list> 

/* TREE TEMPLATE CLASS */ 
template <class T> 
class TreeTemplate 
{ 
    public: 
     TreeTemplate(); 
     void appendChild(T*); 
     int getChildCount(); 
    protected: 
     std::list<T*> m_childList; 
}; 

/* Constuctor */ 
template <class T> 
TreeTemplate<T>::TreeTemplate(){} 

template <class T> 
void TreeTemplate<T>::appendChild(T* t) 
{ 
    m_childList.push_back(t); 
} 

template <class T> 
int TreeTemplate<T>::getChildCount() 
{ 
    return m_childList.size(); 
} 

/* CLASS INHERITTING TEMPLATE */ 
class TreeItem : public TreeTemplate<TreeItem> 
{ 
    public: 
     std::string getTestName(); 
     TreeItem(std::string, std::string); 

    private: 
     std::string m_testID; 
     std::string m_testName; 
}; 

TreeItem::TreeItem(std::string test_id, std::string test_name) 
{ 
    m_testID = test_id; 
    m_testName = test_name; 
} 

std::string TreeItem::getTestName() 
{ 
    return m_testName; 
} 

/* MAIN FUNCTION */ 
int main() 
{ 
    TreeItem *myTree = new TreeItem("9", "10"); 
    TreeItem *child1 = new TreeItem("9.1", "10.1"); 
    TreeItem *child2 = new TreeItem(); 

    std::cout << myTree->getTestName() << std::endl; 

    myTree->appendChild(child1); 
    std::cout << myTree->getChildCount() << std::endl; 
    return 0; 
} 

Nun, wenn ich nicht versuchen, einige neue Constructor in abgeleiteten Klasse (das heißt contructor overload) hinzuzufügen, ist alles gut. Aber wenn ich einen neuen Konstruktor hinzufüge (wie das Code-Segment zeigt), kann ich nicht auf den vorhandenen Konstruktor (der Basis-Template-Klasse) zugreifen. Ich erhalte folgende Fehlermeldung in der Zeile TreeItem *child2 = new TreeItem();

enter image description here

Bin ich dumm hier etwas zu tun? Ich kann andere Methoden überladen, nur bei Constructor fehlschlagen. Wie kann ich den vorhandenen Konstruktor der Basisvorlagenklasse überladen?

+1

Sie benötigen einen Standardkonstruktor zu implementieren, wenn Sie eine benutzerdefinierte Konto haben, setzen Sie einfach 'TreeItem() {}' 'in Ihrem TreeItem' Klasse. – George

+0

Nur ein Hinweis - warum muss der Benutzer einen Zeiger auf Ihre 'TreeTemplate' Klasse geben? Wenn ich ein einfaches 'int' im Baum speichern möchte, warum muss ich Speicherlecks riskieren, indem ich' new int' für alle Ganzzahlen mache, die ich speichern möchte? Eine gute Klasse arbeitet mit Werttypen - wenn der Benutzer wirklich Zeiger speichern möchte, dann werden sie Ihre Klassenzeiger zum Speichern geben. Zum Beispiel vergleiche 'std :: vector ' und 'std :: vector '. Wenn ich Zeiger auf Widget gespeichert haben möchte, erkläre ich das letztere. – PaulMcKenzie

+0

@George, So, sobald ich einen neuen Konstruktor in der abgeleiteten Klasse deklariere, verliere ich den Zugriff auf den Konstruktor (die Konstruktoren) der Basisklasse? –

Antwort

0

Es gibt zwei Probleme zu lösen. Die erste besteht darin, dass bei der Definition eines Konstruktors für einen Typ der Standardkonstruktor dieses Typs nicht implizit generiert wird. Sie können es erzwingen, indem Sie = default verwenden. Hier ist ein Beispiel.

struct Foo { 
    Foo() = default; // Allows default construction 
    Foo(int value) : m_value(value) {} 
    int m_value; 
}; 

Das zweite Problem ist, dass ein abgeleiteter Typ seine Konstruktoren der Elternklasse nicht erbt. Wie kann im folgenden Beispiel ein Konstruktor des Typs Base eine Instanz des Typs Derived konstruieren? Base ist nicht bekannt Derived 's Mitglieder.

class Base { 
public: 
    Base(int x, int y) : m_x(x), m_y(y) {} 
private: 
    int m_x; 
    int m_y; 
}; 

class Derived : public Base { 
public: 
    Derived(int x, int y, int z) : Base(x, y), m_z(z) {} 
private: 
    int m_z; 
}; 

void foo() 
{ 
    // If we use Base's constructor, what is m_z? 
    // Won't compile 
    Derived bar(1, 2); 
} 

Nur die Konstrukteure des Typs sind Sie tatsächlich Konstruieren berechtigt sind, nicht, dass es Konstrukteurs-Basistypen. Um das Verhalten zu simulieren, müssen Sie neue Konstruktoren für den Parametersatz bereitstellen, den Sie unterstützen möchten.

class Derived : public Base { 
public: 
    Derived(int x, int y, int z) : Base(x, y), m_z(z) {} 
    Derived(int x, int y) : Base(x, y), m_z(0) {} 
private: 
    int m_z; 
}; 

In bestimmten Fällen, indem ein variadische Template-Konstruktor wie das folgende Beispiel, um dieses Problem umgehen können. Dies sollte nicht im Allgemeinen gemacht werden, nur wenn es einen bestimmten Bedarf gibt.

#include <utility> 

class Base { 
public: 
    Base(int x, int y) : m_x(x), m_y(y) {} 
private: 
    int m_x; 
    int m_y; 
}; 

class Derived : public Base { 
public: 
    template<class ... Args> 
    Derived(Args&&... args) : Base(std::forward<Args>(args)...) {}; 
}; 

void foo() 
{ 
    Derived b(1, 2); 
}