3

While searching for methods for overloading Subscript('[]') operator for template class, I came across two different techniques.

First Technique:

Overloading the operator [] returning pointer to the container directly, which will allow both reading value and assigning value. A sample implementation of this technique:

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];
    }

};

With main() as:

X<int> sample(100);
cout<<sample[9]<<endl;
sample[9]=9;
cout<<sample[9]<<endl;

Output:

0
9

Second Technique:

Second technique involves declaring a proxy class and overloading the operator = via that class. A sample implementation of this technique:

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);
    }

};

With same main() we get same output.

I personally like the second method. But, I really want to compare these two methods. What are the major functional difference of these two techniques. What advantages each of these method have?

4

3 回答 3

4

如果您想公开一系列未按原样存储(需要从存储转换到存储)或不能简单地通过引用访问的元素,则可以使用您描述的基于代理的技术。一个例子是 std::vector < bool >:它在存储中的每个字节(每个位一个)中打包八个 bool。以这种方式存储它们,不可能返回对单个此类布尔值的引用,因此索引运算符返回一个“代理对象”来支持对包含的布尔值的读取和写入。

如果您可以返回对存储对象的直接引用,那么将其包装在代理中并没有真正的优势,除非您想限制分配(例如,只允许容器中的正值)。

于 2014-04-10T06:35:54.110 回答
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%,但在不需要时最好避免使用。

于 2014-04-10T08:15:29.930 回答
2

通常,当您想要返回与数据的内部存储不匹配的内容时,会使用代理。经典示例是二维矩阵,其元素存储在单个数组中。如果您提供一个运算符来返回行或列,则需要代理。另一个例子是臭名昭著的std::vector<bool>,其中数据不需要存储为 的块bool,但访问必须返回bool给用户。

代理可用于返回内部数据表示的段的不同“视图”。在您的示例中,似乎没有理由使用它们。

于 2014-04-10T06:37:48.163 回答