Set*_*gie 7 c++ iterator interface covariance
我有一个特定的类来存储一段数据,它实现了一个接口:
template<typename T>
class MyContainer : public Container<T> {
class Something : public IInterface {
public:
// implement *, ->, and ++ here but how?
private:
T x;
};
// implement begin and end here, but how?
private:
Something* data; // data holds the array of Somethings so that references to them can be returned from begin() and end() to items in this array so the interface will work, but this makes the problem described below
};
Run Code Online (Sandbox Code Playgroud)
而且我有一系列Something的.
我需要Something实现一个接口类(IInterface在示例中):
*retval返回到基准x构件,retval->返回的地址x,并且++retval使retval参考下Something在数组中.container[i](其中,container是阵列保持Something的对象)始终返回的东西,使得*retval总是返回到相同的参考T针对相同i.现在,界面看起来像这样:
template<typename T>
class Container {
class IInterface {
public:
virtual T& operator*() = 0;
virtual T* operator->() = 0;
virtual IInterface& operator++(); // this is the problem
};
// returning a reference right now to support covariance, so subclasses can
// derive from Container and then have a member class derive from IInterface
// and override these to return their derived class, but this has a problem
virtual IInterface& begin() = 0;
virtual IInterface& end() = 0;
};
Run Code Online (Sandbox Code Playgroud)
我目前的解决方案(有虚方法返回IInterface&,并返回一个Something&在执行)与要求没有问题,除了为++retval要求.因为Something它直接绑定到它所持有的对象并且不能T用指针指向a,所以我无法找到++使变量引用Something数组中的下一个.
如果有帮助知道,这是一个迭代器类型系统.我会用STL样式迭代器(你只有一个数组T)来实现它,它们通过值传递并保持指向它们所代表的值的指针,但这会破坏接口,因为只有引用和指针是协变的,并且对象已经必须存在于其他地方(在我的代码中它们在数组中),因此您不会返回对本地对象的引用.
这个设置的目的是让人们可以编写一个函数来接收Container&和迭代容器而不知道它是什么类型的容器:
void iterate(Container<int>& somecontainer) {
Container<int>::IIterator i = somecontainer.begin(); // right now this would return a reference, but it doesn't/can't work that way
while (i != somecontainer.end()) {
doSomething(*i);
++i; // this is the problem
}
}
Run Code Online (Sandbox Code Playgroud)
这对我来说很难描述,如果您需要更多信息,请随时告诉我.
你要做的是称为类型擦除.基本上,您希望提供一个值类型(在整个继承层次结构中是相同的),它包装特定的迭代器类型并提供统一的动态接口.
类型擦除通常使用非虚拟类(擦除类型)实现,该类存储指向实现擦除的虚拟基类的指针,从中派生用于包装每个特定迭代器的不同类型.静态类将提供模板化的构造函数/赋值运算符,它们将动态实例化派生类型的对象并在内部存储指针.然后,您只需要将一组操作实现为对内部对象的调度.
对于最简单的类型擦除形式,您可以看一下boost::any(文档在这里)的实现
草图:
namespace detail {
template<typename T>
struct any_iterator_base {
virtual T* operator->() = 0; // Correct implementation of operator-> is tough!
virtual T& operator*() = 0;
virtual any_iterator_base& operator++() = 0;
};
template <typename T, typename Iterator>
class any_iterator_impl : any_iterator_base {
Iterator it;
public:
any_iterator_impl( Iterator it ) : it(it) {}
virtual T& operator*() {
return *it;
}
any_iterator_impl& operator++() {
++it;
return *this;
}
};
}
template <typename T>
class any_iterator {
detail::any_iterator_base<T>* it;
public:
template <typename Iterator>
any_iterator( Iterator it ) : it( new detail::any_iterator_impl<T,Iterator>(it) ) {}
~any_iterator() {
delete it;
}
// implement other constructors, including copy construction
// implement assignment!!! (Rule of the Three)
T& operator*() {
return *it; // virtual dispatch
}
};
Run Code Online (Sandbox Code Playgroud)
实际的实现变得非常混乱.您需要为标准中的不同迭代器类型提供不同版本的迭代器,并且操作符的实现细节也许并不简单.特别operator->是迭代应用,直到获得原始指针,并且您希望确保您的类型擦除行为不会破坏该不变量或记录您如何破坏它(即T您的适配器可以包装的类型的限制)
对于扩展阅读: - 关于面向对象和C++中的泛型编程之间的张力 - any_iterator:为C++迭代器实现擦除 - adobe any_iterator,