我在代码中使用std :: map来存储数据。使用map的迭代器访问和/或修改元素非常容易,但是因为我真的需要抑制一些操作(比如++,[]等),我不知道它是否属实,但似乎很少文章建议不要直接继承std :: map,所以我正在编写一个包装器。
class MyContainer
{
private:
std::map<int, int> data;
public:
int &operator[](int); // here we write the interface to control the behavior of accessing the data element
void &operator++();
void &operator--();
};
但这导致了另一个问题。实际上,我在代码中的每个地方使用迭代器来访问/修改元素。但是在地图移动到自定义类之后,我不能再使用主程序中的迭代器来处理数据了。有人建议编写我自己的迭代器,但在阅读了几篇文章之后,似乎人们建议通过继承std :: iterator来自定义我们自己的迭代器。这似乎很简单但对我来说仍然太抽象。我有两个疑惑
1)我将迭代map,但我的包装器实际上不是一个容器。并且为了控制地图元素上的以下操作(++, - ,[])的行为,我应该让自定义迭代器引用MyContainer而不是map。这似乎让我感到困惑,因为我们需要提前映射,但迭代器会引用包装器。我不知道如何使它工作,有什么例子我可以遵循类似的情况?感谢。
2)我不希望代码直接访问map元素,因此,我已经在包装器中定义了运算符
int &operator[](int)
在上面的函数中,返回的引用取决于输入参数,也就是说,对于某些情况,它可以返回NULL引用而不是引用元素。但是如果返回NULL,则以下调用不再有效
data[3]++;
因为data [3]可以返回空引用。但是如何在更新元素之前检查返回的引用是否为null?
答案 0 :(得分:2)
我认为为元素'++
运算符等实现特殊行为是过度的。同样,对于迭代器的递增和递减操作。我认为一个好的解决方案就是将绑定检查添加到[]
访问器中,并在必要时抛出一个超出范围的异常。因此,请使用地图的begin()
和end()
方法,并将绑定检查添加到[]
:
class MyContainer
{
private:
std::map<int, int> data;
public:
typedef std::map<int, int> MapType;
typedef MapType::iterator iterator;
typedef MapType::const_iterator const_iterator;
typedef MapType::reference reference;
public:
iterator begin() {return data.begin();}
const_iterator begin() const { return data.begin();}
// and so on ...
reference operator[](size_t i) {
if (data.size()<=i) { /* raise exception here */ }
return data[i];
}
const reference operator[](int) const { /* same as above */}
};
这样做的好处是返回类型与标准库容器的类型相匹配。
答案 1 :(得分:0)
如果您需要迭代它,可以让您“公开”公开。 否则,不要提供迭代接口,在里面做所有事情(需要迭代)。