Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;Getter/Setter(替代方案?)_C++ - Fatal编程技术网

C++ C++;Getter/Setter(替代方案?)

C++ C++;Getter/Setter(替代方案?),c++,C++,好吧,几乎我读到的每一个地方,我都读到能手/二传手是“邪恶的”。 现在,作为一个经常在PHP/C#中使用getter/setter的程序员,我看不出它们是如何存在的。我已经读到他们破坏了封装等等,然而,这里有一个简单的例子 class Armor{ int armorValue; public: Armor(); Armor(int); //int here represents armor value int GetArmorValue(); void SetArmorV

好吧,几乎我读到的每一个地方,我都读到能手/二传手是“邪恶的”。 现在,作为一个经常在PHP/C#中使用getter/setter的程序员,我看不出它们是如何存在的。我已经读到他们破坏了封装等等,然而,这里有一个简单的例子

class Armor{

  int armorValue;
public:
  Armor();
  Armor(int); //int here represents armor value
  int GetArmorValue();
  void SetArmorValue(int);
};
现在,让我们说“能手”和“二传手”是“邪恶的”。 初始化后如何更改成员变量

例如:

Armor arm=Armor(128); //armor with 128 armor value

//for some reason I would like to change this armor value
arm.SetArmorValue(55); //if i do not use getters / setters how is this possible?
不管出于什么原因,让我们说上述情况都不好。 如果我的游戏将护甲值限制在1到500之间呢。(任何护甲的护甲数都不能超过500或少于1)

现在我的实现变得

void Armor::SetArmor(int tArmValue){
      if (tArmValue>=1 && tArmValue<=500)
         armorValue=tArmValue;
      else
         armorValue=1;
}
void Armor::SetArmor(int tArmValue){

如果(tArmValue>=1&&tArmValue您误解了某些内容。不使用getter/setter会破坏封装并暴露实现细节,对于某些邪恶的定义,可以将其视为“邪恶”

我猜想他们在某种意义上可以被认为是邪恶的,没有适当的IDE编辑器支持,他们在C++中有点写…

一个C++陷阱是创建非const参考吸引子,它也允许修改。这与返回指向内部数据的指针一样,并且将锁定内部实现的那部分,并且确实不比生成字段公共。


编辑:根据评论和其他答案,你听到的可能是指总是为每个领域创建非私有的getter和setter。但我也不会称之为邪恶,只是愚蠢;-)

简言之:它们不是邪恶的


只要它们不泄露内部表示,就没有问题。我看这里没有问题。

你的getter/setter看起来不错


getter/setter的替代方法是公开成员变量。更准确地说,将变量分组到没有成员函数的结构中。并在类中对该结构进行操作给成员访问减少了封装,但有时这是必要的。最好的方法是使用getter和setter。有些人们在不需要访问的情况下实现它们,只是因为它们可以,而且这是一种习惯

如果不使用getter/setter,我将如何施加此限制?如果不使用getter/setter,我将如何修改属性

您可以检查从变量读取的内容,如果其值超出范围,请改用预定义值(如果可能)


您也可以使用肮脏的黑客手段,例如保护变量下面的内存不被写入,捕获写入尝试,以及禁止/忽略具有无效值的尝试。这将是一个很麻烦的实现过程,执行起来也很昂贵。不过,它可能对调试有用。

无论何时:

  • 它们直接访问类的数据成员
  • 每次向类添加数据时都必须添加新的getter
  • 每个getter中的数据行为都不同
  • 因此,优秀的获取者将执行以下操作:

  • 它们将请求转发给其他对象或从多个位置收集数据
  • 您可以使用一个getter获取大量数据
  • 您获取的所有数据都以相同的方式处理

  • 另一方面,二传者总是邪恶的。

    有点逆向:是的,获取者和二传者(又名访问者和变异者)大多是邪恶的

    在我看来,这里的罪恶与其说来自“破坏封装”,不如说来自简单地将变量定义为一种类型(例如,
    int
    )当它真的不是那种类型时。看看您的示例,您将Armor称为
    int
    ,但它实际上不是。虽然它无疑是一个整数,但它肯定不是
    int
    ,这(除其他外)定义一个范围。虽然您的类型是一个整数,但它根本不支持与
    int
    相同的范围。如果您希望
    Armor
    的类型是从1到500的
    整数,请定义一个直接表示该类型的类型,并将
    Armor
    定义为该类型的实例。在这种情况下,由于要强制执行的ant被定义为类型本身的一部分,您不需要在其上附加setter来尝试强制执行它

    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), val_(init.val_)
        { }
    
        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;
        }
    };
    
    当然,我上面给出的也有点简单。对于您的装甲类型,支持
    -=
    (可能还有
    +=
    )可能会很方便,因此攻击会以
    x.armor-=10;
    结束

    一句话:getter和setter的主要问题(或者至少是“一个”)是,它们通常指向您定义了一个变量作为一种类型,而实际上您需要某种其他类型的变量,而这种类型恰好在一些方面类似


    <>现在,有些语言(例如java)不能给程序员提供编写代码所需的工具。这里我相信C++的标记使用表明你确实想写C++。C++确实为你提供了必要的工具,(至少IMO)。您的代码将更好地利用它提供的工具,这样您的类型将强制执行所需的语义约束,同时仍然使用干净、自然、可读的语法。

    对get/set函数的一个常见批评是,客户端代码可能会滥用它们来执行逻辑上应该封装在类中的操作。例如,假设一个客户想要“抛光”他们的盔甲,并决定其效果是增加“价值”到了20岁,他们就开始做自己的小动作,很开心。然后其他地方的其他客户代码决定rusty armour的值应该降低30,他们也尽了自己的一份力。与此同时,客户代码中的其他十几个地方也允许对armour进行抛光和生锈处理,以及说“加固”和“开裂”,并直接实施。这方面没有中央控制……装甲级的维护者没有能力做以下事情:

    • 有锈迹,
      bounded<int> armor(1, 500);
      
      saturating<int> armor(1, 500);
      
      armor = 1000;
      
      std::cout << armor;  // prints "500"