【问题标题】:c++ class members functions: how to write these functions?c++ 类成员函数:如何编写这些函数?
【发布时间】:2015-04-02 23:27:24
【问题描述】:

在我的面向对象 c++ 课程中,我们必须编写我放在下面的这个类。

Point
    class Point{
    public:
        Point( double x = 0, double y = 0 );
        double getX() const;
        double getY() const;
        Point & setX( double x );    //  mutator, returning reference to self
        Point & setY( double y );
        const Point & output() const;
        double distance( const Point & other ) const;
    private:
        double xPoint, yPoint;
    }; // class Point

我的问题是...我找不到任何关于函数 setX、setY 和 output 应该如何工作的信息。它们与类本身的类型相同,我已经写了我希望它们看起来像下面的内容。谁能告诉我我做错了什么以及这些功能如何工作的更多细节? setX 函数应该改变对象中的 xPoint,setY 应该对 yPoint 做同样的事情,而 output 应该简单地输出它们。

Point & Point::setX( double x )
{
xPoint = x;
}   

Point & Point::setY( double y )
{
Ypoint = y;
}

const Point & Point::output() const
{
cout << xPoint << yPoint;
}

【问题讨论】:

  • 只需在 setX 和 setY 的末尾添加一个 return *this:您正在返回对您的类的引用,例如,您可以这样做:p0.setX(1.23).setY(3.45),当然还有 @987654325 @Point 的一个实例。在输出函数中,在 xPoint 和 yPoint 之间放置一个分隔符,就像一个空格。你说They are the same type as the class itself :不要将变量类型与函数/方法返回的类型混淆:这些方法返回它们所属类的实例。
  • 您在setY 中还有一个小错字:应该是yPoint,而不是Ypoint。 C++ 区分大小写。
  • 非常感谢!您能否详细说明为什么将 *this 指针用于这些函数?

标签: c++ class oop object


【解决方案1】:

只需在 setX 和 setY 的末尾添加 return *this;:您将返回对对象的引用,例如,您可以这样做:p0.setX(1.23).setY(3.45),当然 p0 是 Point 的一个实例。在输出函数中,在 xPoint 和 yPoint 之间放置一个分隔符,就像一个空格。您说They are the same type as the class itself:不要将变量类型与函数/方法返回的类型混淆:方法setXsetYoutput 返回对它们所属类的实例的引用。注意输出返回的引用是const,所以可以这样做:

p0.setX(1.23).setY(3.45).output();

但不是:

p0.output().setX(1.23);

因为setX 不是一个 const 方法(它没有声明它不会修改它所属的类实例中的数据)。

您可以改为调用:

double x = p0.output().getX();

因为getX 是一个 const 方法。

注意:我并不是说你应该以这种方式使用这些方法,但重点是展示你可以做什么。

【讨论】:

    【解决方案2】:

    Setter 是公共方法,允许您更改类的私有成员,它们没有返回类型,因此 setXsetY 应该是 void 而不是 Point

    void set(double x); // Declaration
    void Point::setX( double x ) // Definition outside Point.h
    {
       xPoint = x;
    } 
    

    output 相同应该是void,其余的很好你可以定义它任何你想显示的,你可以像这样改变它:

    void Point::output() const
    {
      cout << "(" << xPoint << ", " << yPoint << ")";
    }
    

    【讨论】:

    • 我完全同意,但这是我的教授希望我们做的,我们将它们视为无效,我们必须更改它们。
    【解决方案3】:

    setX() 可能会更改pointX 成员的值,并返回对正在操作的对象的引用。

    所以实现可能类似于

    Point &Point::setX(double xval)
    {
        if (IsValid(xval)) pointX = xval;    // ignore invalid changes
        return *this;
    }
    

    这可以(假设其他成员函数和运算符被正确使用)用于这样的事情

    #include <iostream>
     // declaration of Point here
    int main()
    {
         Point p;
         std::cout << p.setX(25).setY(30).getX() << '\n';
    }
    

    虽然这个例子不是特别有用(它展示了什么是可能的),但成员函数调用的链接在各种情况下都很有用。例如,这种技术实际上是iostream 插入和提取运算符工作的基础,并允许在单个语句中向流中插入/提取多个内容。

    【讨论】:

      【解决方案4】:

      setXsetY 函数的文档说

      // mutator, returning reference to self
      

      你的实现做了变异,但是你没有完成这个函数应该满足的契约:它应该返回对自身的引用

      this 是指向您正在调用该方法的对象的指针,因此添加该行

      return *this;
      

      将完成合同。


      这是一个旁白,但它可以帮助您理解为什么有人会想要使用这种“奇怪”的设计。

      您可能熟悉以如下方式使用的普通赋值

      a = b = 0;
      
      if((result = some_function()) == 0) {
          // Do something in the `result == 0` case
      } else {
          // Do something in the `result != 0` case
      }
      

      和其他类似的东西。第一个示例将ab 都设置为0。第二个示例将函数调用的返回值存储到变量result中,然后根据该值是否为0进行分支。

      其工作方式是x = y 是一个二元运算符,它的副作用是将y 的值复制到x,然后返回该值(技术上是引用x),以便它可以在周围的表达式中使用。

      因此,当您编写a = b = 0 时,它会被解析为a = (b = 0),并具有使b 为零的效果,然后计算为a = 0,然后对其进行计算并使a 为零。对于分支示例也是如此。

      这是人们在编写代码时喜欢做的事情(这是一个完全独立的话题),所以当人们使用 operator= 方法设计新类型时,他们设计它们来支持这种用法,通过使它们返回对分配给的对象的引用。例如

      MyClass& MyClass::operator=(arg a)
      {
          // Copy the value of `a` into this object
          return *this;
      }
      

      其他赋值运算符,如 operator+= 也以这种方式工作。

      现在,当您习惯了这种用法时,只需将其扩展到其他类似赋值的函数,例如setXsetY。这具有额外的便利,可以轻松地进行链式修改,如 point.setX(3).setY(7)

      【讨论】:

      • 非常感谢!现在我明白 '*this' 是一个取消引用的指针,*this 通常指向当前对象的克隆,但由于它返回一个引用,所以它返回到当前对象。如果没有星号,我们无法返回它的原因是什么?
      猜你喜欢
      • 2018-06-29
      • 1970-01-01
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多