具有子类容器的子类的非标准迭代器
nonstandard iterator for subclass with containers of subclasses
>很抱歉这很长,但我不知道如何让它更短,并且仍然显示我问题的重要特征。
即使我已经想出了如何做我想做的事情的想法,我也会问这个问题,但它需要以与标准迭代器模式不匹配的方式实现迭代器。 我想就如何以更标准或更好的方式做到这一点提出任何建议。
我有一个抽象的基类。 它的任何子类都会有一些对象集合。 我想将一些通用代码放在基类中,这些代码需要迭代集合中的所有对象。 集合中的对象都将从另一个抽象基类派生,但将是子类对象。 可能有多个来自 multible 子类的对象集合,并且这些集合可能是不同的集合类型。 我真正想做的是这样的:(注意:此代码无法编译。
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool operator!=(iterator& other) = 0;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
int processCollections()
{
iterator it;
int sum = 0;
for(it = begin(); it != end(); ++it)
{
sum += (*it).someInterface(7);
}
return sum;
}
};
然后我想要一些CollectionObjectBase和MyObjectBase的子类,如下所示:
class CollectionObject1 : public CollectionObjectBase { ... }
class CollectionObject2 : public CollectionObjectBase { ... }
class CollectionObject3 : public CollectionObjectBase { ... }
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::vector< CollectionObject2>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
class MyObjectB : public MyObjectBase
{
public:
std::vector<CollectionObject1> someThings;
std::set< CollectionObject3> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::vector<CollectionObject1>::iterator it1;
std::set< CollectionObject3>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
上面的代码有一些大问题。 首先,MyObjectBase::begin() 和 MyObjectBase::end() 不能返回 MyObjectBase::iterator ,因为 MyObjectBase::iterator 是一个抽象类,无论如何你都不想这样做,因为你实际上想要一个知道如何迭代 MyObjectBase 子类中的集合的 MyObjectBase::itrator 子类。 您需要返回对 MyObjectBase::iterator 的引用。
第二个问题来自MyObjectA::iterator::operator!=()。 你想做这样的事情:
virtual bool operator!=(iterator& other)
{
return it1 != other.it1 || it2 != other.it2;
}
但是要成为MyObjectBase::iterator::operator!=()的重载,它必须采用MyObjectBase::iterator&类型的参数,并且没有成员it1和it2。 我想到解决这个问题的最好主意是用函数atEnd()替换运算符!=(),因为在此代码中使用它的唯一用途是检测迭代器是否在末尾,但它使它真正非标准。
最后,MyObjectA::begin() 和 MyObjectA::end() 不能返回临时。 请记住,我们必须返回对 MyObjectBase::iterator 的引用,该引用指向 MyObjectA::iterator,而不是复制构造 MyObjectBase::iterator。 我想到的解决这个问题的最好主意是用new分配迭代器,当我这样做时,我需要返回一个指针,而不是一个引用,以便调用者可以删除它。 这是我的最终代码。 它工作并执行迭代器的功能,但它是非标准的。 谁能想到一种使用符合标准模式的迭代器来做到这一点的方法?
#include <map>
#include <vector>
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool atEnd() = 0;
};
virtual iterator* begin() = 0;
int processCollections()
{
iterator* it;
int sum = 0;
for (it = begin(); !it->atEnd(); ++it)
{
sum += (**it).someInterface(7);
}
delete it;
return sum;
}
};
class CollectionObject1 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 1;
}
};
class CollectionObject2 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 2;
}
};
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::map<int, CollectionObject1>::iterator it1End;
std::vector< CollectionObject2>::iterator it2;
std::vector< CollectionObject2>::iterator it2End;
iterator(std::map<int, CollectionObject1>::iterator it1Init, std::map<int, CollectionObject1>::iterator it1EndInit,
std::vector< CollectionObject2>::iterator it2Init, std::vector< CollectionObject2>::iterator it2EndInit) :
it1(it1Init),
it1End(it1EndInit),
it2(it2Init),
it2End(it2EndInit)
{
// Initialization handled by initialization list.
}
virtual CollectionObjectBase& operator*()
{
if (it1 != it1End)
{
return (*it1).second;
}
else
{
return *it2;
}
}
virtual iterator& operator++()
{
if (it1 != it1End)
{
++it1;
}
else
{
++it2;
}
return *this;
}
virtual bool atEnd()
{
return it1 == it1End && it2 == it2End;
}
};
virtual MyObjectBase::iterator* begin()
{
return new iterator(someThings.begin(), someThings.end(), otherThings.begin(), otherThings.end());
}
};
无用的答案有一个问题。 考虑 Impl 和 Base 的这些子类:
class MyImpl : public Base::Iterator::Impl {
public:
MyImpl(std::vector<CollectionObjectSub>::iterator itInit) : it(itInit) {}
CollectionObjectBase& operator*() { return *it; }
void operator++() { ++it; }
// bool operator==(Base::Iterator::Impl const &other) const { it == other.it; }
bool operator==(MyImpl const &other) const { it == other.it; }
private:
std::vector<CollectionObjectSub>::iterator it;
};
class Sub : public Base {
public:
Iterator& begin() { return Iterator(new MyImpl(collection.begin())); }
private:
std::vector<CollectionObjectSub> collection;
};
Sub 包含一个向量,MyImpl 包含一个向量迭代器。 我想实例化一个 Base::Iterator,impl_指向 MyImpl。 如果MyImpl::operator==需要一个MyImpl&,那么它不会重载Base::Iterator::Impl::operator==,但如果它需要一个Base::Iterator::Impl&,那么即使它实际上是一个MyImpl,我也无法访问矢量迭代器。
似乎我需要做一个动态演员来获得一个需要RTTI的MyImpl。 我听说如果可能的话要避免使用RTTI。 还有别的办法吗?
因此,您想按值返回迭代器,但其动态类型是否根据您调用的begin
/end
的覆盖而变化?没问题 - 只需添加另一层间接。
class Base {
public:
class Iterator {
public:
struct Impl {
virtual ~Impl() {}
virtual CollectionObjectBase& operator*() = 0;
virtual void operator++() = 0;
virtual bool operator==(Iterator::Impl const &other) const = 0;
};
Iterator() {}
explicit Iterator(std::unique_ptr<Impl> &&i) : impl_(std::move(i)) {}
Iterator(Iterator &&other) = default;
CollectionObjectBase& operator*() { return **impl_; }
Iterator& operator++() { ++*impl_; return *this; }
bool operator==(Iterator const &other) const {
return (!impl_ && !other.impl_) || (*impl_ == *other.impl_);
}
private:
std::unique_ptr<Impl> impl_;
};
// ...
这使用指针指向 impl (pimpl) 习惯用法为每个具体的子类Base
提供它自己的具体子类 Base::Iterator::Impl
,但仍然允许您使用移动语义按值传递Base::Iterator
对象,以转移动态对象的所有权。
铌。我使两个默认构造的(nullptr)迭代器比较相等,因此您无需为end
创建真实实例。
- 子类化标准::时间::d
- Vulkan-hpp 是reinterpret_casting非标准布局类到另一个类.这合法吗?
- 基类中的虚拟方法和子类中的非 Virtula 方法.仍然如何调用子类方法,即使它是非虚拟的
- 错误 C4839:非标准地使用类 'ATL::CW2AEX<520>' 作为可变参数函数的参数
- 在 C++17 中为非标准布局类"conditionally-supported""偏移"意味着什么?
- 如何在尝试为某些非类型值实例化模板子类方法时产生编译器错误
- 是否可以覆盖(隐藏)非虚拟方法,但仍然从子类显式调用它
- 非标量类型子类错误
- 具有子类容器的子类的非标准迭代器
- 如何重写模板化子类中的非模板化方法
- 警告C4238:使用了非标准扩展:类右值用作左值
- 对非标准布局类的布局限制
- 非托管类方法:非标准语法;使用 '&' 创建指向成员的指针
- 非静态/静态/全局/子类成员的初始化顺序
- 将非纯虚函数转换为子类中的纯虚函数
- 为什么子类的非重写实例方法中的"this"类型是父类型?
- 从子类调用非虚方法
- 使用父模板类的非依赖嵌套类作为子类中的成员
- 子类继承的非公共虚函数会发生什么情况
- 我必须在c++中的类定义中包含非标准库吗?