【问题标题】:C++ Template Inheritance Issues (Warnings and Errors)C++ 模板继承问题(警告和错误)
【发布时间】:2018-02-10 09:53:31
【问题描述】:

我正在尝试模仿 C++ 中通用列表的 .Net 实现。

我将各种 interfaces 充实为纯虚拟抽象类,如下所示:

template <typename T>
class ICollection {

public:
    virtual void Add(T item) = 0;
    virtual void Clear(void) = 0;
    virtual bool Contains(T item) = 0;
    virtual void Remove(T item) = 0;

    virtual int32_t Count(void) const = 0;

};

template <typename T>
class IList : public ICollection<T> {

public:
    virtual T Item(int32_t index) = 0;
    virtual int32_t IndexOf(T item) = 0;
    virtual void Insert(int32_t index, T item) = 0;
    virtual void RemoveAt(int32_t index) = 0;

};

现在,当我尝试如下实现我的主要 List 类时:

template <typename T>
class List : public IList<T>, public ICollection<T> {

public:
    List(void);
    List(int32_ capacity);

    // ICollection<T>
    void Add(T item);
    // other functions from ICollection

    // IList<T>
    T Item(int32_t index);
    // other functions from IList

    void AddRange(IList<T> items);

private:
    typedef vector<T> ListType;

    ListType *m_pList;
};


template <typename T>
List<T>::List(void) {
    m_pList = new ListType();
}

template <typename T>
void List<T>::Insert(uint32_t index, T item) {
    // Insert an entry into the list at the specified offset
    m_list->insert(index, item);
}

// Implementation of other functions here...

只要我尝试如下使用List&lt;T&gt; 类:

List<int32_t> myList;

出现警告:

In instantiation of 'class List<long int>':
    required from here
warning: direct base 'ICollection<long int>' inaccessible in 'List<long int>' due to ambiguity [enabled by default]

class List : public IList<T>, public ICollection<T> {
       ^

随后出现以下错误:

In instantiation of 'void List<T>::Insert(uint32_t, T) [with T = long int; uint32_t = long unsigned int]':
    required from here
error: no matching function for call to 'std::vector<long int, std::allocator<long int> >::insert(uint32_t&, long int&)'

m_list->insert(index, item);
^

note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::iterator, const value_type&) [with _Tp = long int; _Alloc = std::allocator<long int>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<long int*, std::vector<long int, std::allocator<long int> > >; typename std::_Vector_base<_Tp, _Alloc>::pointer = long int*; std::vector<_Tp, _Alloc>::value_type = long int]

 vector<_Tp, _Alloc>::
 ^

 note:   no known conversion for argument 1 from 'uint32_t {aka long unsigned int}' to 'std::vector<long int, std::allocator<long int> >::iterator {aka __gnu_cxx::__normal_iterator<long int*, std::vector<long int, std::allocator<long int> > >}'

如果我修改List&lt;T&gt; 类的声明以删除IList&lt;T&gt;ICollection&lt;T&gt; 抽象类,则不会产生错误。

我猜我使用模板化基类的方式在这种情况下是不正确的。

【问题讨论】:

  • 您有多个问题:1) C++ 中的对象不像 .NET 或 Java 对象那样工作,它们根本不同 2) 多重继承。有关更多信息,请获取一本好的 C++ 书籍。这些是无法在简短的 stackoverflow.com 答案中完全解释的基本概念。试图依靠您对 .NET 的了解来学习 C++ 会导致无穷无尽的失败和困惑,因为正如我所说,C++ 对象的工作方式完全不同。例如,您是否知道所有方法都必须将 const 引用作为参数,而不是值?原因请参阅您的 C++ 书籍。
  • 感谢您的 cmets。 1)我完全理解这一点。 2)我不需要一本好书,也不是试图“学习 C++”,但我试图理解为什么模板系统或我的实现,在这种情况下,由于多重继承而产生错误。不依赖 .Net 的任何知识 - 事实上,我已经有一段时间没有接触过它了。
  • 对于初学者来说,这与模板无关。相同的编译错误将发生在相同的类结构和图片中任何地方没有模板的情况下。如果你“试图理解”一些关于 C++ 的东西,无论是模板还是其他任何东西,一本好的 C++ 书都是必需的。 C++ 模板不是类,类也不是模板(与 .NET 或 Java 不同,它们完全不像 C++ 模板,即使它们看起来非常相似),错误是由于类继承,而不是与模板相关的任何内容。
  • [OT] 您可以通过直接使用vector 而不是vector 上的指针来避免问题(0/3/5 规则)。

标签: c++ templates inheritance abstract-class


【解决方案1】:

此问题与模板没有直接关系。

class A {
    public void f() {}
};

class B : public A {};

class C : public A, public B {};

int main() {
    C c;
    c.f(); // Error: ambiguous base class!
}

当你继承一个类时,派生类包含一个基类的对象,称为基类子对象。所以在我的例子中,每个B 都包含一个A。每个C 都包含一个A 和一个B。问题是,当我尝试将f 作为C 的成员调用时,编译器需要找到A 子对象来调用它。但是有两个具有这种类型的子对象!一个是直接被C继承的,一个是在继承的B子对象里面。所以编译器无法理解我的意思。

在这种情况下的解决方案是不要继承一个类两次。在我的示例中,C 不需要直接继承 A,因为继承 B 将为它提供间接的 A 子对象并访问其所有成员。

在您的情况下,List&lt;T&gt; 不需要直接继承 ICollection&lt;T&gt;。从IList&lt;T&gt; 派生就足够了。

(在其他情况下,使用“虚拟继承”可能很有用,它告诉编译器“只为这种类型创建一个基类子对象,即使我在某个派生类中多次间接继承它”。但是就目前的情况而言,这对于您的代码来说可能是多余的。)

【讨论】:

  • 感谢您的评论。理解您关于不需要从ICollection&lt;T&gt; 继承的观点,我只是不确定ICollection&lt;T&gt; 函数在List&lt;T&gt; 类中的可见性,但鉴于它标记为public,这有点明显。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多