2017-01-12 6 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), все хорошо. Но если я добавляю новый конструктор (как показывает сегмент кода), я не могу получить доступ к существующему конструктору (класса базового шаблона). Я получаю следующее сообщение об ошибке в строке TreeItem *child2 = new TreeItem();

enter image description here

Я делаю что-то глупое здесь? Я могу перегружать другие методы, только сбой в Constructor. Как я могу перегрузить существующий конструктор базового шаблона?

+1

Вам нужно реализовать конструктор по умолчанию, если у вас есть обычай один, просто положить 'TreeItem() {}' в классе 'TreeItem'. – George

+0

Только некоторые советы - почему пользователь должен предоставить указатель на ваш класс «TreeTemplate»? Если я хочу сохранить простой «int» внутри дерева, почему мне нужно рисковать утечками памяти, выполняя «новый int» для всех целых чисел, которые я хочу сохранить? Хороший класс работает со значениями типов - если пользователь действительно хочет хранить указатели, тогда они будут указывать указатели на классы. Например, сравните 'std :: vector ' и 'std :: vector '. Если я хочу, чтобы указатели на Widget сохранены, я объявляю последнее. – PaulMcKenzie

+0

@George, Итак, как только я объявляю новый конструктор в производном классе, я теряю доступ к конструктору (-ам) базового класса? –

ответ

0

Есть две проблемы для решения. Во-первых, когда вы определяете конструктор для типа, конструктор по умолчанию этого типа не создается неявно. Вы можете заставить его использовать = default. Вот пример.

Вторая проблема заключается в том, что производный тип не наследует конструкторы класса родителя. Интуитивно, в следующем примере, как может конструктор типа 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; 
}; 

В некоторых случаях вы можете обойти эту проблему путем подачи VARIADIC конструктора шаблона, как в следующем примере. Этого не следует делать в целом, только когда есть определенная потребность.

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