c++类中成员setter /getter的适当设计

Proper design of member setters/getters in a C++ class

本文关键字:getter 成员 setter c++      更新时间:2023-10-16

为类成员设计setter和getter的通常方法如下

class QNumber 
{
    public:
        void setNumber(unsigned int xNumber){ this->mValue = xNumber; };
        unsigned int getNumber(void) const { return this->mValue; };
    private:
        unsigned int mValue;
}

如果成员是另一个类(例如QRational而不是unsigned int),那么从性能方面考虑,getter最好返回一个引用。

所以修改后的设计应该是

class QNumber 
{
    public:
        const QRational & value(void) const  { return  mValue;} // getter
              QRational & value(void)        { return  mValue;} // 'setter'
    private:
        QRational mValue;
}

我的问题是——后一种方法是不是有潜在的问题?我在其他人的代码中很少看到它,对我来说,它似乎比set/get方法更优雅。

很多谢谢,丹尼尔

getter和setter的作用是将接口与实现分开。如果返回一个引用,它必须指向实现中的某个地方。现在,如果您更改了实现,您将不得不开始按值返回。

当不太可能需要其他任何东西时,我个人更喜欢public非静态成员。引用语义的getter和setter提供了这两个世界中最坏的情况。(不过,我正在制定一项改进方案。)

除了Potatoswatter的回答,请注意另外一点。

你的第二个设计激发了以下形式的使用:

QRational& r = number.value(); 
// or
const QRational& r = number.value(); 
因此,用户保留对内部对象的引用。如果您的number对象可以被破坏或移动,而r仍然在那里,这将有点难以管理。这甚至不取决于是否使用const或非const方法。

第一个设计没有暴露这样的问题。

至少在我看来,如果该成员的行为类似于无符号整型(例如,允许对无符号整型赋值),并且您确实确定该类应该支持对该成员的直接操作(即,它应该有"getter"answers"setter"),那么您至少应该使访问它干净,而不是要求围绕该实现细节编写其他代码。为了避免这种情况,您应该定义此对象的类型与普通unsigned int的区别,然后在正确且直接定义该类型的类中实现该行为。

class QNumber { // bad name--looks like a Qt class name
    unsigned int value;
public:
    QNumber(unsigned int value = 0) : value(value) {}
    QNumber &operator=(unsigned int val) { value = val; return *this; }
    operator unsigned int() { return value; }
};

有了这个,客户端代码可以是可读的——而不是像x.SetNumber(2);x.SetNumber() = 2;那样的丑陋,你只使用x = 2;。这也避免了当您让客户端获得指向类内部的指针或引用(通常应该避免)时出现的各种生命周期问题。