getter 和 setter、指针或引用,以及在 c++ 中使用的良好语法?

发布于 2024-08-08 13:40:45 字数 663 浏览 2 评论 0原文

我想知道 C++ getter 和 setter 的良好语法。

private:
YourClass *pMember;

我猜 setter 很简单:

void Member(YourClass *value){
  this->pMember = value; // forget about deleting etc
}

那么 getter 呢? 我应该使用引用还是常量指针?

示例:

YourClass &Member(){
   return *this->pMember;
}

或者

YourClass *Member() const{
  return this->member;
}

它们之间有什么区别?

谢谢,

编辑:

抱歉,我将编辑我的问题...我了解引用和指针,我问的是引用和常量指针,作为吸气剂,它们在我的代码中有何区别,就像在未来一样,如果我采取某种方式,我应该期望失去什么......

所以我想我会使用 const 指针而不是引用

const 指针不能被删除或设置,对吗?

I would like to know a good syntax for C++ getters and setters.

private:
YourClass *pMember;

the setter is easy I guess:

void Member(YourClass *value){
  this->pMember = value; // forget about deleting etc
}

and the getter?
should I use references or const pointers?

example:

YourClass &Member(){
   return *this->pMember;
}

or

YourClass *Member() const{
  return this->member;
}

whats the difference between them?

Thanks,

Joe

EDIT:

sorry, I will edit my question... I know about references and pointers, I was asking about references and const pointers, as getters, what would be the difference between them in my code, like in hte future, what shoud I expect to lose if I go a way or another...

so I guess I will use const pointers instead of references

const pointers can't be delete or setted, right?

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

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

发布评论

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

评论(8

月寒剑心 2024-08-15 13:40:46

+1 关于质疑 setter 和 getter 的使用。如果必须使用它们并且有可能出现空值,请考虑使用 boost::shared_ptr。这样就可以为您处理所有权。

+1 on questioning the use of setters and getters. If you must use them and have the possibility of nulls consider using boost::shared_ptr. This way ownership is handled for you.

鸵鸟症 2024-08-15 13:40:46

乔纳森,你使用什么编译器? shared_ptr 很可能已经作为编译器 TR1 实现的一部分附带了。

Jonathan, what compiler are you using? There's a great chance that shared_ptr already comes shipped with it as part of the compiler's TR1 implementation.

吾性傲以野 2024-08-15 13:40:45

作为一般规律:

  • 如果 NULL 是有效参数或返回值,则使用指针。
  • 如果 NULL 不是有效参数或返回值,请使用引用。

因此,如果可能应该使用 NULL 调用 setter,请使用指针作为参数。否则请使用参考。

如果调用包含 NULL 指针的对象的 getter 是有效的,它应该返回一个指针。如果这种情况是非法不变量,则返回值应该是引用。如果成员变量为 NULL,则 getter 应该抛出异常。

As a general law:

  • If NULL is a valid parameter or return value, use pointers.
  • If NULL is NOT a valid parameter or return value, use references.

So if the setter should possibly be called with NULL, use a pointer as a parameter. Otherwise use a reference.

If it's valid to call the getter of a object containing a NULL pointer, it should return a pointer. If such a case is an illegal invariant, the return value should be a reference. The getter then should throw a exception, if the member variable is NULL.

一笔一画续写前缘 2024-08-15 13:40:45

您的代码看起来很像您习惯于一种不同的语言 - 在 C++ 中使用 this->x (例如)相对不常见。当代码写得很好时,使用访问器或修改器也同样如此。

尽管我在这方面相当不寻常,但我将(再次)记录下来说,强制客户端代码直接使用访问器或修改器是一个坏主意。如果确实存在客户端代码操作对象中的值有意义的情况,那么客户端代码应该使用正常的赋值来读取和/或写入该值。

当/如果您需要控制分配什么值时,运算符重载可以让您进行控制,而无需在客户端代码上强制使用丑陋的 get/set 语法。具体来说,您想要的是代理类(或类模板)。仅举一个例子,人们想要获取/设置函数的最常见情况之一是类似于应该限制在某个特定范围内的数字。 setXXX 检查新值是否在范围内,getXXX 返回该值。

如果你想要这样,一个(相当)简单的模板可以更干净地完成工作:

template <class T, class less=std::less<T> >
class bounded {
    const T lower_, upper_;
    T val_;

    bool check(T const &value) {
        return less()(value, lower_) || less()(upper_, value);
    }

    void assign(T const &value) {
        if (check(value))
            throw std::domain_error("Out of Range");
        val_ = value;
    }

public:
    bounded(T const &lower, T const &upper) 
        : lower_(lower), upper_(upper) {}

    bounded(bounded const &init) 
        : lower_(init.lower), upper_(init.upper)
    { 
        assign(init); 
    }

    bounded &operator=(T const &v) { assign(v);  return *this; }

    operator T() const { return val_; }

    friend std::istream &operator>>(std::istream &is, bounded &b) {
        T temp;
        is >> temp;

        if (b.check(temp))
            is.setstate(std::ios::failbit);
        else
            b.val_ = temp;
        return is;
    }
};

这也使代码更接近于自我记录 - 例如,当你声明一个对象时: bounded(1 , 1024);,很明显,意图是 1 到 1024 范围内的整数。有人可能发现唯一有疑问的是 1 和/或 1024 是否是包含在范围内。这与在类中定义 int 有很大不同,并期望每个查看过该类的人都意识到他们应该使用 setXXX 来对可以的值强制执行一些(此时未知的)边界集。分配的。

当您将其中一个变量嵌入到类中时,您将其设为公共变量,并且范围仍然是强制的。在客户端代码中,语法上没有真正的争论——您只是分配给一个公共变量,就像您分配任何其他变量一样——有一个小细节,即尝试分配超出范围的值将引发异常。理论上,该类可能应该采用策略模板参数来准确指定它在这种情况下的作用,但我从来没有真正的理由为此烦恼。

Your code looks a great deal as if you're accustomed to a different language -- in C++ using this->x (for one example) is relatively unusual. When the code is at all well written, so is using an accessor or mutator.

Though I'm fairly unusual in this particular respect, I'll go on record (yet again) as saying that forcing client code to use an accessor or mutator directly is a bad idea. If you honestly have a situation where it makes sense for client code to manipulate a value in your object, then the client code should use normal assignment to read and/or write that value.

When/if you need to control what value is assigned, operator overloading lets you take that control without forcing ugly get/set syntax on the client code. Specifically, what you want is a proxy class (or class template). Just for one example, one of the most common situations where people want get/set functions is something like a number that's supposed to be restricted to some particular range. The setXXX checks the new value for being in range, and the getXXX returns the value.

If you want that, a (fairly) simple template can do the job much more cleanly:

template <class T, class less=std::less<T> >
class bounded {
    const T lower_, upper_;
    T val_;

    bool check(T const &value) {
        return less()(value, lower_) || less()(upper_, value);
    }

    void assign(T const &value) {
        if (check(value))
            throw std::domain_error("Out of Range");
        val_ = value;
    }

public:
    bounded(T const &lower, T const &upper) 
        : lower_(lower), upper_(upper) {}

    bounded(bounded const &init) 
        : lower_(init.lower), upper_(init.upper)
    { 
        assign(init); 
    }

    bounded &operator=(T const &v) { assign(v);  return *this; }

    operator T() const { return val_; }

    friend std::istream &operator>>(std::istream &is, bounded &b) {
        T temp;
        is >> temp;

        if (b.check(temp))
            is.setstate(std::ios::failbit);
        else
            b.val_ = temp;
        return is;
    }
};

This also makes the code much closer to self documenting -- for example, when you declare an object like: bounded<int>(1, 1024);, it's immediately apparent that the intent is an integer in the range of 1 to 1024. The only part somebody might find open to question is whether 1 and/or 1024 is included in the range. This is considerably different from defining an int in the class, and expecting everybody who ever looks at the class to realize that they're supposed to use the setXXX to enforce some (at that point unknown) set of bounds on the values that can be assigned.

When you embed one of these in a class, you make it a public variable, and the range is still enforced. In the client code, there's no real argument over syntax -- you're just assigning to a public variable, like you would any other -- with the minor detail that attempting to assign a value that's out of range will throw an exception. In theory, the class should probably take a policy template-parameter to specify exactly what it does in that case, but I've never had a real reason to bother with that.

孤城病女 2024-08-15 13:40:45

最好的事情是向客户端提供一个真正的 OO 接口,隐藏实现细节。 Getter 和 Setter 不是面向对象的。

The best thing is to provide a real OO interface to the client that hides implementaton details. Getters and Setters are not OO.

ゞ花落谁相伴 2024-08-15 13:40:45

正如其他人所说,如果可能为 null,则使用指针。

在大多数情况下,我更喜欢尽可能使用参考文献。就我个人而言,在我的代码中,我喜欢使用指针和引用之间的区别来表示所有权。我认为带有引用的调用是将对象“借用”给另一个函数或类。传递或返回引用的原始类仍然拥有它,并负责它的创建、维护和清理。另一方面,当我的代码传递非常量指针时,通常意味着正在进行某种所有权的转移或共享,以及随之而来的所有责任。

(是的,我通常使用智能指针。这些类似于我脑海中的引用。我正在谈论比这里更低级别的代码。)

As others have said, use pointers if null is a possibility.

In most cases, I prefer to use references when possible. Personally, in my code, I like to use the distinction between pointers and references to signal ownership. I think of calls with references as "loaning" an object to another function or class. The original class that passed or returned the reference still owns it, and is responsible for its creation, maintenance and clean up. When my code passes a non-const pointer, on the other hand, it usually means that there's some kind of transfer or sharing of ownership going on, with all the responsibilities that entails.

(And yes, I usually use smart pointers. Those are akin to references in my mind. I'm talking about lower level code than that here.)

如果没结果 2024-08-15 13:40:45

它们有什么区别?

引用是事物的别名(它事物*)。指针是事物的地址。如果所指向的内容有可能不存在,那么您可能不想返回引用。参考资料告诉呼叫者“我将给您一个别名,当我将其返回给您时,该别名将存在”。事实上,确实没有办法检查引用以查看其底层内容是否有效。

从语义上讲,使用指针意味着调用者可能希望在使用它之前检查 Member 是否存在。通常这是通过 NULL 检查来完成的。

最终没有“正确”的答案。这取决于班级的合同以及调用者是否愿意/应该/想要检查“Member”是否仍然存在。

简短的答案是指向可以指向其他地方的内容的指针以及“未就座”别名的引用。

whats the difference between them?

The reference is an alias of the thing(it is the thing*). A pointer is the address of the thing. If there's a chance that what's pointed to won't be there, then you probably don't want to return references. References tell the caller "I'm going to give you an alias that will exist when I return it to you". In fact there's really no way to check the reference to see if what's underlying is valid.

With the pointer, semantically, you are implying that the caller may wish to check to see if Member exists before using it. Ussually this is done with a NULL check.

Ultimately there's no "right" answer. It depends on the class's contract and if the caller will/should/wants to check whether "Member" is still around.

The short answer is pointers for things that can be pointed elsewhere and references for "unseated" aliases.

ら栖息 2024-08-15 13:40:45

除了其他答案之外,如果您选择 getter 的引用,请不要像示例中那样编写:

YourClass &Member(){
   return *this->pMember;
}

您的 getter 实际上允许设置,如 instance->Member() = YourClass(); 从而绕过你的设置器。如果 YourClass 是不可复制的,则可能不允许这样做,但这仍然是需要记住的另一件事。另一个缺点是 getter 不是 const。

相反,像这样编写 getter:

const YourClass &Member() const {
   return *this->pMember;
}

In addition to the other answers, if you choose references for the getter don't write it like in your example:

YourClass &Member(){
   return *this->pMember;
}

Your getter actually allows setting, as in instance->Member() = YourClass(); and thus bypassing your setter. This might not be allowed if YourClass is noncopyable, but is still another thing to have in mind. Another drawback is the getter is not const.

Instead, write your getter like this:

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