2017-01-12 9 views
0

Treeのすべての機能(つまり、appendChildchildCount)を含むC++ Templateクラスを設計しようとしています。このテンプレートクラスからextendにして、既存の機能を持つカスタムTreeクラス(Methods)と追加機能を設計したいと思います。C++テンプレートクラスの継承の理解

これまでのところ私はこれを得ました。私は(つまりコンストラクタoverload)派生クラスでいくつかの新しいコンストラクタを追加しようとしていない場合

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

今、すべてが良いです。しかし、(コードセグメントが示すように)新しいコンストラクタを追加する場合、(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

解決すべき2つの問題があります。 1つは、型のコンストラクタを定義すると、その型のデフォルトのコンストラクタが暗黙的に生成されないということです。 = defaultを使用すると、強制的に使用することができます。ここに例があります。

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

第2の問題は、派生型が親のクラスのコンストラクタを継承しないということです。直観的に、次の例では、型Baseのコンストラクタは、型Derivedのインスタンスをどのように構築できますか? BaseDerivedのメンバーの気にしていません。

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); 
} 
関連する問題