2

下面是一个例子:

在圈子.h

class circle
{
    double _radius;
public:
    double getRadius() {return _radius;}
    void setRadius(double r) {_radius=r;} 
}

在主要

int main()
{
    circle a;
    cout<<a.getRadius();    // I want to use "a.radius"
    a.setRadius(3.2);       // I want to use "a.radius=3.2"
}

那么第一个问题是为什么我们应该使用 get 和 set 函数来访问实例变量而不是直接访问它们?第二个问题是如何做运算符重载,让get和set的函数调用看起来简洁(就像objective-c那样)?

4

5 回答 5

5

当然,使您希望的语法可用的最简单方法是创建_radius一个名为的公共成员radius

class circle
{
public:
    double radius;
}

现在你可以像这样使用它:

circle c;
c.radius = 10.0;

但是,您不应该仅根据您希望如何编写代码(或者您可能如何在 C# 中编写代码)来做出此类决定。我建议您为每个成员考虑以下几点:

  1. 直接设置成员有意义吗?也许成员只是对象状态的私有部分,并受其他成员函数的影响。考虑以下示例,您真正想要公开的接口只是一个增加 大小的函数circle

    class circle
    {
    public:
        circle(double radius, double delta = 1.0)
          : radius(radius), delta(delta) { }
    
        double increaseSize() {
          radius += delta;
          return radius;
        }
    private:
        double radius;
        double delta;
    }
    
  2. 您需要强制执行不变量吗?考虑一下,也许,你已经决定不可能circle有负半径的 a 这样的东西。您可能希望通过使用一个成员函数来检查给定的新半径以确保它大于 0 来强制执行此操作。

  3. 您想通过界面提供成员的一些不同表示吗?也许您希望circle保留其作为成员的半径,但任何客户唯一想知道的是它的区域。您可以将其设为radius私有,然后提供getArea如下函数:

    class circle
    {
    public:
        circle(double radius)
          : radius(radius) { }
    
        double getArea() {
          return PI * radius * radius;
        }
    private:
        double radius;
    }
    
  4. 以上几点可能目前都不适用,但将来可能会适用。如果您有这种远见,最好现在提供 getter 和 setter 函数。这确保了客户端使用的接口以后不会改变。

作为 getter 和 setter 的另一种命名方案,简单地拥有两个重载函数是很常见的——一个用于设置,一个用于获取——如下所示:

class circle
{
public:
    void radius(double); // Set the radius
    double radius();     // Get the radius
private:
    double radius;
}
于 2013-04-09T13:05:27.803 回答
2

回答第一个问题:因此您的对象被封装,您可以处理更改的内部表示或在半径更改时需要修改/更新。

第二个:你不能。C++ 不支持这样的对象获取器和设置器。

(这实际上几乎是可能的,但它真的不值得)

于 2013-04-09T12:54:56.053 回答
1
  1. 使用 setter 和 getter 执行此操作有多种原因;

    • 它们提供了更好的封装;类的内部变量的实际值应该是类设置/获取的责任,而不是类实例用户的责任。但是在这个问题上有不同的思想流派。
    • 他们留下了在调用 setter/getter 时做更多事情的可能性。例如,

      class circle
      {
          double _radius;
          double _perimeter;
      
      public:
      
          double getRadius() {return _radius;}
      
          void setRadius(double r) {
                  _radius = r;
                  _perimeter = 2*M_PI*r;
          } 
      };
      
  2. 好吧,您指示的方式可以简单地通过创建radius一个公共变量来完成:) 但是,请考虑这种替代方法:

    class circle
    {
    private: 
        double _radius;
    
    public:
        const double &radius;
    
        circle(double R)
            : radius(R)
            : radius(_radius)   
        {}
    
        void setRadius(double r) {
            _radius = r;
        } 
    };
    

    然后将像这样使用:

    cout << a.radius;    // works
    a.radius = 3.2;      // produces error
    a.setRadius(3.2);    // works
    

    这种方法的好处是简洁,可能更直观的 getter(即使用实际的变量名),更简洁的代码(不需要无数几乎空的 getter),甚至可能提高性能(对 getter 函数的调用比直接访问变量,尽管这取决于编译器优化设置)。

这里提到的所有方法都有优点和缺点。最后,这完全取决于您的团队/雇主的偏好。

于 2013-04-09T13:13:06.820 回答
0

您使用 getter 和 setter 来实现更好的封装,并以更简单的方式更改底层实现。

关于第二个问题:你不能那样做。您将不得不编写一个 getter 和 setter 方法。

于 2013-04-09T12:56:03.483 回答
0

那么有初始化方法:

OCD::OCD ( ) : _number( 0 )
{
}

和体内构造方法:

OCD::OCD ( size_t initial_value )
{
  _number = initial_value;
}

要在类实例中访问它们,只需使用变量名:

  _number = value;

但如果你有一个同名的全局、局部或参数变量,你可以像这样具体:

  this->_number = value;

然后从实例外部你可以这样调用它:

  // (that is if _number was public)
  std::cout << "ocd2._number    => " << ocd2._number << std::endl;
  std::cout << "ocd3p->_number  => " << ocd3p->_number << std::endl;

方法也是如此:

  std::cout << "ocd2.get( )     => " << ocd2.get() << std::endl;
  std::cout << "ocd3p->get( )   => " << ocd3p->get() << std::endl;

请参阅我关于该主题的要点:https ://gist.github.com/LaughingSun/7d2330ccff0777bec106

于 2015-11-29T07:03:17.590 回答