我希望这不会过于复杂。我试过在互联网上搜索了一段时间,虽然我发现很多Q / As处理模板,继承等,但我找到的资源都没有处理这个特定的问题:
我想为std::vector<T>
创建一个包装器,它只会创建std::vector<MyClass>
类型的向量或其任何继承的类。
这基本上看起来像:
Class Base;
Class Derived : Base;
template <Base T> class myVector{
public:
void add(T);
protected:
std::vector<T> list;
}
目标是能够拥有一个具有以下行为的库:
Base A;
Derived D;
int i;
myVector<A> AVector; // This should work
myVector<D> DVector; // This should work
myVector<i> iVector; // This should NOT work
AVector.add(A); // This should work
AVector.add(D); // This should work (through polymorphism)
DVector.add(D); // This should work
DVector.add(A); // This should not work
有人可以评论上述问题/例子吗?我的最终目标是用c ++编写自己的基本事件处理。在这种情况下,A将是c#EventArgs的类似物。 B将允许特定的EventArgs类型。我毫不怀疑Boost等人有类似的功能,但我想暂时避开这条路线。
在实践中,代码会起作用(基于我在互联网上找到的教程):
template<EventArgs arg> class Event{
typedef void (*fptr)(arg);
std::vector<fptr> listeners;
}
void notifylisteners(arg){
for (typename std::vector<fptr>::iterator iter = listeners.begin(); iter != listeners.end; ++iter)
(**iter)(arg); // there should be a check for a valid reference, in case one of the function pointers becomes invalid
声明
Event<myEventHandlerType> myEvent;
将有效地与C#代码起作用:
public event myEventHandlerType myEvent;
由于依赖std :: vector,此实现需要模板。在这里使用非类型参数模板(如果它有效)的好处是它会强制使用特定的eventArg参数类型传递给所有已注册的处理程序,并且在编译期间错误将失败。
任何想法或评论都将不胜感激。
迈克尔
答案 0 :(得分:2)
如果您使用的是C ++ 11,则可以访问std :: is_base_of&lt;&gt;和static_assert()
当使用无法强制转换为Base的类型传递myVector时,可以使编译器给出错误。
#include <type_traits>
class Base
{};
class Derived : public Base
{};
template <class T>
class Foo
{
public:
Foo()
{
static_assert (std::is_base_of<Base,T>::value, "Error: Type T not derived from Base");
}
};
class Lol
{
};
Foo<Derived> foo1;
Foo<Lol> foo2; //Static assert fails
(请参阅此处的编译器输出http://ideone.com/NAXSA)
如果您没有C ++ 11支持,那么您需要更多的工作,但仍然可以完成。请参阅此处有关https://stackoverflow.com/a/4532302/564944
的信息答案 1 :(得分:1)
我希望我能正确理解你的描述。 C ++这样做的方式不是通过继承,也不会“强制”传入继承自A
的类型。而是使用duck typing:如果它看起来像鸭子,走路就像一只鸭子,像鸭子一样嘎嘎叫,然后它就像一只鸭子,不管它的“官方”类型。
具体而言,myVector<T>
只会接受任何类型T
。如果您尝试对其不支持的T
对象执行某些操作(例如使用特定arg
调用它),则它将在编译时失败。
当然,记录T
需要支持的操作的签名是一个好主意 - 实质上是它实现的接口。
(旁注:C ++ 0x“概念”的概念可以让你在代码中表达这一点,但它已经从标准中删除了。)