C ++模板继承问题(警告和错误)

时间:2017-09-01 10:39:56

标签: c++ templates inheritance abstract-class

我试图模仿C ++中通用List的.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<T>类时如下:

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<T>类的声明以删除IList<T>ICollection<T>抽象类,则不会生成错误。

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

1 个答案:

答案 0 :(得分: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都包含AB。问题是,当我尝试将f作为C的成员调用时,编译器需要找到A子对象来调用它。但是有两种类型的子对象!一个是C直接继承的,另一个是继承的B子对象。所以编译器无法弄清楚我的意思。

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

在您的情况下,List<T>不需要直接继承ICollection<T>。只需从IList<T>派生出来就足够了。

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