在搜索模板类的下标(' []')运算符的方法时,我遇到了两种不同的技术。
第一种技术:
直接将operator []
返回指针重载到容器,这将允许读取值和赋值。该技术的示例实现:
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
T& operator [](int indx)
{
return container[indx];
}
};
main()
为:
X<int> sample(100);
cout<<sample[9]<<endl;
sample[9]=9;
cout<<sample[9]<<endl;
输出:
0
9
第二种技术:
第二种技术涉及声明代理类并通过该类重载operator =
。该技术的示例实现:
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
class Proxy
{
int indx;
X<T> &parent;
public:
Proxy(X<T> &p, int x) : parent(p),indx(x)
{
}
void operator =(T assgn)
{
parent.container[indx]=assgn;
}
operator T const &()
{
return parent.container[indx];
}
friend class X<T>;//unnecessary line, I know!
};
Proxy operator[](int indx)
{
return Proxy(*this,indx);
}
};
使用相同的main()
,我们得到相同的输出。
我个人喜欢第二种方法。但是,我真的想比较这两种方法。这两种技术的主要功能区别是什么?这些方法各有哪些优点?
答案 0 :(得分:3)
如果您希望公开一系列未按原样存储的元素(需要从存储转换到存储)或者不能简单地通过引用访问,则可以使用您描述的基于代理的技术。一个例子是std :: vector&lt; bool&gt;:它在存储中的每个字节(每位一个)中包含八个bool。以这种方式存储它们,不可能返回对单个这样的bool的引用,因此索引操作符返回“代理对象”而不是支持读取和写入所包含的bool。
如果可以返回对存储对象的直接引用,除非您想限制赋值,否则将它包装在代理中没有任何实际优势(例如,只允许容器中的正值) )。
答案 1 :(得分:2)
通常,当您想要返回与数据的内部存储不匹配的内容时,会使用代理。典型的例子是2D矩阵,元素存储在单个数组中。如果您提供运算符来返回行或列,则需要代理。另一个例子是臭名昭着的std::vector<bool>
,其中数据不需要存储为bool
的块,但访问必须向用户返回bool
。
代理可用于返回不同的&#34;视图&#34;内部数据表示的段。在您的示例中,似乎没有理由使用它们。
答案 2 :(得分:2)
为大多数客户端使用获取代理对象相当棘手......例如,如果有人说:
tcp_peer.send_from_iterator_range(&sample[2], &sample[7+1]);
如果sample::operator[]
返回临时代理,并且该代理没有小心地替换operator&
,则代码会自行询问代理的地址。
在不失去代理拦截读取和/或写入数据的能力的情况下,无法支持某些客户端使用,例如...
Container::element_type& ref = container[n];
ref = 20;
...客户端代码假定容器operator[]
将产生对实际元素的引用。 operator[]
返回的任何代理必须提供operator element_type&()
- 移交此类引用并将其自身脱离游戏 - 或拒绝(例如仅返回const
引用,返回临时的非const
引用无法绑定的值)并强制编辑客户端代码。
因此,当你需要代理时,代理的95%是好的,但是当你不需要代理时,最好避免使用代理。