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

Jon*_*han 10 c++ getter setter pointers reference

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

private:
YourClass *pMember;
Run Code Online (Sandbox Code Playgroud)

我猜这个setter很简单:

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

和吸气剂?我应该使用引用还是常量指针?

例:

YourClass &Member(){
   return *this->pMember;
}
Run Code Online (Sandbox Code Playgroud)

要么

YourClass *Member() const{
  return this->member;
}
Run Code Online (Sandbox Code Playgroud)

他们之间有什么区别?

谢谢,

编辑:

对不起,我将编辑我的问题...我知道引用和指针,我问的是引用和常量指针,作为getter,它们在我的代码中会有什么区别,比如在未来,我希望什么样的shoud如果我去某种方式会失败...

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

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

RED*_*AIR 15

作为一般法律:

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

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

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


小智 7

最好的方法是为客户端提供真正的OO接口,隐藏实现细节.Getters和Setters不是OO.

  • 实际上,这可能值得拥有自己的问题.但作为一个简单的例子,假设你在游戏中有一个角色,你想尝试向北移动.你可以调用getX()和getY()来获取它的位置,为它们添加正确的值,调用map对象来查看该位置是否空闲,以及调用setX()和setY()来更新它的位置.但是,如果你对角色有一个move()方法,那么你就集中了那个逻辑.您现在可以自由更改角色存储位置的方式,而无需遍历代码.现在,AI和播放器控件都可以使用这种常用方法. (9认同)
  • 我认为DevFred的建议是避免使用getter/setter和公共变量.相反,尝试定义为您工作的活动方法. (6认同)
  • getter和setter是非常Java/C#风格(不是C++).它们是这些语言依赖于反射和框架来构建对象的结果.Getters和Setter破坏了语言的OO性质,并明确允许您插入对象的内部结构.这在C++中是皱眉的,因为在构造函数完成后让对象完全形成更常见. (6认同)
  • 你能给我一个这个"主动方法"等的例子吗?如果我没有公开变量并且没有创建getter或setter,那么我应该如何使用该类?O_o对不起,如果这有点傻,但我真的没有得到它:( (3认同)

Jer*_*fin 7

你的代码看起来很像,因为你已经习惯了不同的语言 - 在C++中使用this->x(例如)是相对不寻常的.当代码写得很好时,使用访问器或增变器也是如此.

虽然我在这方面非常不寻常,但我会再次记录(强调)迫使客户端代码直接使用访问器或更改器是一个坏主意.如果你真的有一种情况,即客户端代码操纵对象中的值是有意义的,那么客户端代码应该使用正常的赋值来读取和/或写入该值.

当/如果您需要控制分配的值时,运算符重载允许您在不对客户端代码强制获取/设置语法的情况下执行该控制.具体来说,您想要的是代理类(或类模板).仅举一个例子,人们想要获取/设置函数的最常见情况之一就是一个应该限制在某个特定范围内的数字.该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;
    }
};
Run Code Online (Sandbox Code Playgroud)

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

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

  • 对不起,但看一下这段代码比起吸气剂或二传手更难理解(至少对我而言).我觉得创建一个模板化的类或只是一个简单规则的类比一个简单的set函数更好是不容易的.想想一个将被其他库或可执行文件使用的大型库,我认为重载赋值运算符不是最好的方法,当然我只是一个新手,但从我一直在阅读的,赋值运算符应该只有在严格需要时才会超载,比如马丁在我的其他帖子中写的树的规则 (2认同)
  • 如果你要写的只是一个吸气剂和一个二传手,你就是对的 - 这个代码会更复杂.但是,当您可以使用一个模板替换数十个(可能数百个)getter和setter时,它会大大简化代码.无论如何,它集中了所有的复杂性.getter和setter需要*all*代码才能了解实现并增加处理它的复杂性.这将所有复杂性放在一个地方,并简化了所有其他代码. (2认同)