【问题标题】:Understanding inheritance on C++ template class了解 C++ 模板类的继承
【发布时间】:2017-01-12 17:45:14
【问题描述】:

我正在尝试设计一个 C++ Template 类,它将包含 Tree 的所有功能(即 appendChildchildCount)。然后我想从这个模板类中extend 并设计具有现有功能(读作Methods)以及额外功能的自定义 Tree 类。

到目前为止,我得到了这个。

#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(); 行中收到以下错误@

我在这里做傻事吗?我可以重载其他方法,只是在构造函数中失败。如何重载基模板类的现有构造函数?

【问题讨论】:

  • 如果您有自定义构造函数,则需要实现默认构造函数,只需将 TreeItem(){} 放入您的 TreeItem 类中。
  • 只是一些建议——为什么用户必须提供指向您的TreeTemplate 类的指针?如果我想在树中存储一个普通的int,为什么我需要为我想要存储的所有整数执行new int 来冒内存泄漏的风险?一个好的类适用于值类型——如果用户真的想存储指针,那么他们会给你的类指针来存储。例如比较std::vector&lt;Widget&gt;std::vector&lt;Widget*&gt;。如果我想存储指向 Widget 的指针,我声明后者。
  • @George,所以,一旦我在派生类中声明了一个新的构造函数,我就无法访问基类的构造函数?
  • @PaulMcKenzie,我一定会小心谨慎地调用delete 以释放main 末尾的所有这些指针。只是避免了这些,以使我的主要问题更容易理解。
  • @SurajeetBharati -- 您可以使用simple example, like this 复制整个问题。鉴于您在该链接上看到的内容,您知道如何解决该错误吗?

标签: c++ templates inheritance tree


【解决方案1】:

有两个问题需要解决。第一个是当你为一个类型定义一个构造函数时,该类型的默认构造函数不会隐式生成。您可以使用= 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多