2017-01-12 114 views
0

我想設計一個C++ Template類,它將包含Tree(即appendChild,childCount)的所有功能。然後,我想從此模板類中獲取extend,並設計具有現有功能的自定義樹類(讀爲Methods)以及額外的功能。瞭解C++模板類繼承

到目前爲止,我得到了這個。現在

#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; 
} 

,如果我不嘗試添加一些新的構造函數,派生類(即構造器overload),一切都很好。但是,如果我添加一個新的構造函數(如代碼段所示),我無法訪問(Base Template類的)現有構造函數。我收到以下錯誤在該行TreeItem *child2 = new TreeItem();

enter image description here

我在這裏做一些愚蠢的事?我可以重載其他方法,只在構造函數失敗。我如何重載基模板類的現有構造函數?

+1

你需要實現一個默認的構造函數,如果你有一個自定義的,只是把'TreeItem(){}'在'TreeItem'類。 – George

+0

只是一些建議 - 爲什麼用戶必須提供一個指向你的'TreeTemplate'類的指針?如果我想在樹內存儲一個簡單的'int',爲什麼我需要通過爲所有我想存儲的整數執行'new int'來冒內存泄漏的風險?一個好的類可以處理值類型 - 如果用戶真的想存儲指針,那麼他們會給你的類指針來存儲。例如,比較'std :: vector '和'std :: vector '。如果我想要存儲指向Widget的指針,我聲明後者。 – PaulMcKenzie

+0

@George,那麼,只要我在派生類中聲明瞭一個新的構造函數,我就無法訪問基類的構造函數? –

回答

0

有兩個問題需要解決。首先,當你爲一個類型定義一個構造函數時,該類型的默認構造函數不會被隱式生成。你可以強制使用= default。這是一個例子。

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

第二個問題是派生類型不繼承它的父類的構造函數。直觀地說,在以下示例中,Base類型的構造函數如何構造Derived類型的實例? Base不知道Derived的成員。只有

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); 
} 

類型的構造函數你實際上構建符合條件,沒有它的基本類型的構造函數。爲了模擬行爲,你必須爲你想要支持的一組參數提供新的構造函數。

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; 
}; 

某些箱子您可以通過提供一個可變參數模板的構造類似於下面的示例解決此問題。只有在有特殊需要的情況下才能做到這一點。

#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); 
}