没有()的const访问器,或者对成员变量的const引用

时间:2011-03-08 18:24:40

标签: c++ reference accessor

我有兴趣创建一个我可以使用的类,如

class MyClass {
  vector<int> m_vec;
public:
  // Either this
  const& vector<int> vec;
  // Or some version of this. 
  const& vector<int> getVec() { return m_vec } ;

  MyClass() : vec(m_vec) {}
  void changeVec() { m_vec.push_back(5); }
}

现在,如果我想使用getVec(),语法有点麻烦:

myClass.getVec()[5]

我更愿意以某种方式使用

myClass.vec[5]

没有暴露修改载体的能力。 IE,我希望成员变量是私有的,但是变量的const版本是公共的,没有语法或性能开销。

如果我添加const&amp;向量引用,编译器(至少我的GCC版本)实际上使类占用更多内存。所以

  1. 如何在不使用更多内存的情况下为成员变量创建别名,或
  2. 如何避免myVec()[]访问器中的parens?仅定义myVec(int idx)并不是一个令人满意的选项,因为我想在其上调用多个方法。
  3. 为了清楚起见,这是一个例子 - 在实际情况中,使用比矢量情况更具吸引力。此外,内存使用 非常重要,因为许多这些对象存在并将被复制,因此这不是过早的优化。此时,我正在使用getVec()[0]方法,但是丑陋会让我感到害怕。

6 个答案:

答案 0 :(得分:5)

如果出于某种原因,MyClass::operator[]不合适,只需为您的矢量创建一个小包装类。

struct Wrapper {
  friend class MyClass;
  int operator[](size_t s) const { return vec[s]; }
private:
  vector<int> vec;
};

class MyClass {
public:
  Wrapper vec;
};

答案 1 :(得分:4)

你确定你在这里试图解决正确的问题吗?类的一个重要目的是避免将底层实现暴露给用户,在这种情况下你只是做了这样的阐述。

您应该仔细查看您班级的用户API。

真正需要对容器进行哪些操作?您应该以这样的方式设计API,其中方法描述了类的高级过程,而不是“让我了解隐藏的实现细节”。

如果您只需要提供对各种容器元素的访问权限,则可以提供开始/结束迭代器并允许在范围上运行的算法。或者,您可以提供诸如for_each_boysfor_each_girls之类的函数,这些函数将操作数回调到相应的函数。

答案 2 :(得分:3)

作为建议,您可以为operator[]

重载MyClass
int operator[] (size_t which) const {
   return m_vec[which]; 
}

这简化了访问向量的语法:myClass[5]。但是,如果你a)希望用你的类暴露多个向量或b)打算使用其他std::vector成员而不仅仅是数组下标,即size() ...那么你就变得不切实际了。在这种情况下你不能真正避免吸气,从而避免括号。

答案 3 :(得分:1)

最简单的是:

struct MyClass
{
    vector<int> const vec;

    MyClass()
    {
        vector<int>& mvec = const_cast<vector<int>&>(vec);
        // modify mvec
    }
};

答案 4 :(得分:1)

首先要做的事情:我完全没有看到任何意义。现在,如果你打算避免使用()[]语法 - 我坚持认为:我不会 - 你只能提供对该类型的引用。

class test {
   std::vector<int> m_data;
public:
   std::vector<int> &data;
   test() : m_data(), data( m_data ) {}
};

优于包装器的优点是代码更简单,并且没有那么多可能出错的代码。缺点是您泄露了实现的详细信息:外部代码将取决于您提供引用的std::vector实现的对象。请注意,使用包装器在这方面没有太大区别,因为在这两种情况下,您都可以访问详细信息(我将为您提供对我的内部的索引访问),这可能与否是一个好主意。

其他简单的代码,不是很好的解决方案可能意味着使用继承,如:

class test : private std::vector<int>
{
public:
   using std::vector<int>::operator[];
};

这里一个重要的细节是你不应该从STL容器公开继承(事实上,作为class,上面的private关键字是可选,因为继承是默认的私有,但我已将其添加为强调),它们的设计并不适用于多态。通过使用私有继承,您可以限制用户错误的风险,因为向量是一个实现细节。

如果稍后您决定更改另一个容器的向量(允许索引访问 - 再次,您承诺在接口中进行索引访问!),您只需要提供自己的operator[]实现用户代码将编译而无需更改。

答案 5 :(得分:0)

你可以这样做:(不是我认为这是一个特别好的主意......)

class MyClass;

class Proxy{
    public:
    Proxy(MyClass& c); // store reference to c
    int const& operator[](...) const; // access c.vec

    private:
    MyClass& c;
};

class MyClass{
    public:
    // public read-only proxy for this->m_vec
    const Proxy vec;

    MyClass()
        : vec(*this){
    }
    ...
    private:
    vector<int> m_vec;
};

未经测试,但我相信你明白了。这种模式对于提供像数组切片这样的东西很有用。