在C ++中实现侵入式容器时,我遇到了一些奇怪的问题。 鉴于以下简化代码:
struct IFace {
virtual int foo() const = 0;
};
struct Impl : public IFace {
int foo() const { return 111; }
};
template <typename T> struct IntrusiveHook {
T item;
IntrusiveHook<T>* next;
};
template <typename T> struct IntrusiveList {
IntrusiveList() : head(0), tail(0) {}
template <typename U>
void add(IntrusiveHook<U>& addItem) {
if (0 == head) {
head = reinterpret_cast<IntrusiveHook<T>*>(&addItem);
tail = head;
}
else {
tail->next = reinterpret_cast<IntrusiveHook<T>*>(&addItem);
tail = tail->next;
}
}
IntrusiveHook<T>* head;
IntrusiveHook<T>* tail;
};
void testList() {
IntrusiveHook<Impl> impl;
IntrusiveList<IFace> list;
list.add(impl);
// list.head->item.foo();
}
我收到以下错误消息 - 对于“添加” - 调用(当如上所述注释掉行list.head->item.foo()
时):
error C2259: 'IFace' : cannot instantiate abstract class
due to following members:
'int IFace::foo(void) const' : is abstract
testwas.cpp(7) : see declaration of 'IFace::foo'
testwas.cpp(25) : see reference to class template instantiation 'IntrusiveHook<T>' being compiled
with
[
T=IFace
]
testwas.cpp(41) : see reference to function template instantiation 'void IntrusiveList<T>::add<Impl>(IntrusiveHook<Impl> &)' being compiled
with
[
T=IFace
]
在第list.head->item.foo()
行注释时,我得到一个不同的编译错误,前一个被遗漏了(这是一个奇怪的行为,并且在VC ++和gcc编译器上都会发生)
有问题的调用似乎是tail->next = ...
,或者特别是此处使用的抽象类型上的运算符->
。
所以: 如何解决这个问题?
foo
中添加IFace
的默认实施 - 这不是我想要的,但它解决了问题一种hacky解决方案:将tail->next
重写为
reinterpret_cast<IntrusiveHook<U>*>(tail)->next = &addItem;
tail = reinterpret_cast<IntrusiveHook<T>*>(reinterpret_cast<IntrusiveHook<U>*>(tail)->next);
- 但它似乎不适用于VC ++(2010),但使用gcc
......或表演其他一些丑陋的演员
但为什么首先是一个问题?通常,使用运算符“ - &gt;”访问指针类型应该不是问题。
任何帮助将不胜感激。谢谢!
编辑:
为方便起见,我希望IntrusiveHook已经将项目作为实例包含在内。这也是侵入性的伎俩 - 当我做对了 - 只需将指针功能添加到项目而不更改项目本身。 “new”不是一个选项,因为代码应该在没有new
的嵌入式环境中运行。
当然我也想使用带有抽象项的列表,因为using类不会知道实现类。
答案 0 :(得分:2)
据我所知,问题是在IntrusiveHook<T>*
中投射到IntrusiveList::add
。您正在将addItem
投射到IntrusiveHook<IFace>
。 IntrusiveHook<IFace>
的成员item
的成员为IFace
。但是IFace
是抽象的,所以你不能用该类型声明变量 - 你必须使用指针或引用。
所以你必须
IntrusiveHook::item
从T
类型更改为T*
,IntrusiveHook(T* item) : item(item) {}
,impl
中testList()
的声明更改为IntrusiveHook<Impl> impl(new Impl)
list.head->item.foo()
更改为list.head->item->foo()
。如果您不想更改IntrusiveList<IFace*>
,也可以使用IntrusiveList<Impl>
或IntrusiveList<IFace>
代替IntrusiveHook
。