此 C++ 的任何问题; const 引用访问器接口习惯用法?

发布于 2024-09-03 23:54:34 字数 521 浏览 9 评论 0原文

我正在将一个结构转换为一个类,以便我可以为我的变量强制使用 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 引用的样板之外,此方法还有哪些缺点?
有任何奇怪的别名问题吗?
为什么我以前没见过这个成语?

I was converting a struct to a class so I could enforce a setter interface for my variables.
I did not want to change all of the instances where the variable was read, though.
So I converted this:

struct foo_t {
    int x;
    float y;
};

to this:

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

I'm interested in this because it seems to model C#'s idea of public read-only properties.
Compiles fine, and I haven't seen any problems yet.

Besides the boilerplate of associating the const references in the constructor, what are the downsides to this method?
Any strange aliasing issues?
Why haven't I seen this idiom before?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

冷弦 2024-09-10 23:54:34

一个问题是您的类不再可复制或可分配,因此无法存储在向量等 C++ 容器中。另一个原因是,维护您的代码的经验丰富的 C++ 程序员会看到它并惊呼“WTF!!”非常大声,这绝不是一件好事。

One problem is that your class is no longer copyable or assignable, and so can't be stored in C++ containers like vectors. Another is that experienced C++ programmers maintaining your code will look at it and exclaim "WTF!!" very loudly, which is never a good thing.

暗藏城府 2024-09-10 23:54:34

存在别名问题,因为您公开了对 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 对象本身的生命周期之外保留对它本身的引用也是可能的,但这可能更难错过或意外发生。

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

There is an aliasing issue in that because you expose a reference to the foo_t's internal data, it's possible for code external to a foo_t object to hold on to references into its data beyond the object's lifetime. Consider:

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

Or, even simpler:

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

These aren't particularly realistic examples, but this is a potential issue whenever an object exposes or returns a reference to its data (public or private). Of course, it's just as possible to hold on to a reference to the foo_t object itself beyond its lifetime, but that might be harder to miss or to do by accident.

Not that this is an argument against what you're doing. In fact I've used this pattern before (for a different reason) and I don't think there's anything inherently wrong with it, aside from the lack of encapsulation, which you seem to recognize. The above issue is just something to be aware of.

波浪屿的海角声 2024-09-10 23:54:34

您也可以执行类似的操作,这适用于内置类型:
(很抱歉,如果此代码片段包含错误,但您明白了)

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
}

You could also do something like this, which works for built in types:
(Sorry if this code snippet contains errors, but you get the idea)

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
}
一个人的旅程 2024-09-10 23:54:34

你的方法不灵活。当每个变量都有一个 getter / setter 时,这意味着如果您向类中添加某些内容,则不必重写您的 set 方法。

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

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

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


[接下来的一切都是完全主观的]

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

在您的示例中,个人 struct 会更有效,因为它包装了 POD 数据并在逻辑上“结构化”它。

Your approach is not flexible. When you have a getter / setter for every variable it means you don't have to rewrite your set method if you add something to your class.

It's not good because you can't have const and non-const getters (which are used rarely, but sometimes could be useful).

You can't copy references, therefore, your class becomes non-copyable.

Also, having referenced initialized in your class means extra memory and if we're talking about, for example, vertex class (though I think it shouldn't be a class actually), this could become a disaster.


[Everything that follows is completely subjective]

Purpose of getters and setters, to my mind, is not about simple modification, but rather about encapsulating a sequence of actions that results in value modification or returns the value (which we treat as visible result).

Personally struct in case of your example would be more effective, because it wraps POD data and logically "structurizes" it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文