这个C ++ const引用访问器接口习惯用法有什么问题吗?

时间:2010-06-01 19:35:13

标签: c++ const public accessor

我正在将结构转换为类,因此我可以为我的变量强制执行setter接口 但是,我不想更改读取变量的所有实例。 所以我转换了这个:

struct foo_t {
    int x;
    float y;
};

到此:

class foo_t {
    int _x;
    float _y;
public:
    foot_t() : x(_x), y(_y) {  set(0, 0.0);  }

    const int &x;
    const float &y;

    set(int x, float y)  {  _x = x;  _y = y;  }
};

我对此很感兴趣,因为它似乎模仿了C#的公共只读属性的概念 编译很好,我还没有看到任何问题。

除了在构造函数中关联const引用的样板外,这个方法的缺点是什么? 有什么奇怪的别名问题吗? 为什么我以前没见过这个成语?

4 个答案:

答案 0 :(得分:11)

一个问题是你的类不再可复制或可分配,因此不能存储在像vector这样的C ++容器中。另一个是经验丰富的C ++程序员维护你的代码会看到它并惊呼“WTF !!”非常响亮,这绝不是一件好事。

答案 1 :(得分:5)

由于您公开了对foo_t内部数据的引用,因此存在一个别名问题,foo_t对象外部的代码可能会保留对其数据的引用。对象的一生。考虑:

foo_t* f = new foo_t();
const int& x2 = f->x;
delete f;
std::cout << x2; // Undefined behavior; x2 refers into a foo_t object that was deleted

或者,甚至更简单:

const int& x2 = foo_t().x;
std::cout << x2; // Undefined behvior; x2 refers into a foo_t object that no longer exists

这些并不是特别现实的例子,但只要对象公开或返回对其数据(公共或私有)的引用,这就是一个潜在的问题。当然,尽可能在其生命周期之后继续引用foo_t对象本身,但这可能更难以错过或偶然发生。

并不是说这是反对你正在做的事情的论据。事实上,之前我曾经使用过这种模式(出于不同的原因),除了缺乏封装之外,我认为它本身并没有任何错误,你似乎已经认识到了这一点。上述问题只是需要注意的事项。

答案 2 :(得分:2)

你也可以这样做,适用于内置类型: (很抱歉,如果此代码段包含错误,但您明白了这一点)

template <typename T, typename F>
class read_only{
   typedef read_only<T, F> my_type;
   friend F;

public:
   operator T() const {return mVal;}

private:
   my_type operator=(const T& val) {mVal = val; return *this;}
   T mVal;
};


class MyClass {
public:
   read_only <int, MyClass> mInt;
   void MyFunc() {
      mInt = 7; //Works
   }
};

AnyFunction(){
   MyClass myClass;
   int x = myClass.mVal; // Works (okay it hasnt been initalized yet so you might get a warning =)
   myClass.mVal = 7; // Error
}

答案 3 :(得分:0)

您的方法不灵活。如果您为每个变量都有getter / setter,则表示如果您向班级添加内容,则无需重写set方法。

这不好,因为你不能拥有constnon-const getters (很少使用,但有时可能会有用)。

您无法复制引用,因此,您的类将变为不可复制。

另外,在你的类中引用初始化意味着额外的内存,如果我们正在讨论,例如,顶点类(虽然我认为它实际上不应该是一个类),这可能成为一场灾难。


[以下所有内容完全是主观的]

在我看来,getter和setter的目的不是简单的修改,而是封装一系列导致值修改的操作或返回值(我们将其视为可见结果 )。

在你的例子的情况下,个人结构将更有效,因为它包装POD数据并在逻辑上“结构化”它。