【问题标题】:C++ type qualifier problemC++ 类型限定符问题
【发布时间】:2011-08-23 13:32:29
【问题描述】:

作为我的计算机软件开发学位的一部分,我的一个实验室包括创建一个计算器类模板和一个分数类。

问题出在我的分数课上。我现在的任务是重载加号运算符以允许将两个分数相加。

分数.cpp:

#include "Fraction.h"

const Fraction Fraction::operator+ (const Fraction &rhs) const
{
    return Fraction(_num * rhs.GetDen() + (rhs.GetNum() * _den), _den * rhs.GetDen());
}

分数.h

#pragma once

class Fraction
{
    public:
        Fraction(const int &num, const int &den) : _num(num), _den(den) {}
        ~Fraction(void) {}
        const int GetNum(void) { return _num; }
        const int GetDen(void) { return _den; }
        const Fraction operator+ (const Fraction &rhs) const;

    private:
        const int _num, _den;
};

Visual Studio 抱怨我的分数访问器无法“将此指针从 const 分数转换为分数 &”。我完全迷惑了。

【问题讨论】:

    标签: c++ types qualifiers


    【解决方案1】:

    您也需要将访问器限定为 const:

    int GetNum(void) const { return _num; }
    

    顺便说一句,将返回类型限定为 const int 并没有真正意义,无论如何它都会是一个 int。您的编译器应该发出警告。

    【讨论】:

    • 啊哈!我知道这与那些讨厌的常数有关。非常感谢朋友。
    • 这和return (const int)_num;一样吗?还是有同样的效果?
    • @Lee 听起来你接受了 drhirsch 的回答,如果是这样,你应该正式“接受”它。
    • @AtoMerZ 不,该方法必须声明为“const”,本质上承诺不更改对象,以便允许针对 const 对象调用,并且类似于中的注释drhirsch 的回答是,将返回类型声明为“const”是没有意义的,将其转换为“const”同样没有意义,因为调用者总是可以做任何他们的 copy 返回值。
    • 在声明末尾添加 const 意味着它可以被该类的 const 实例调用。这也意味着成员变量在该函数的范围内被视为 const,除非它们已声明为 mutable
    【解决方案2】:

    您的 GetNum 和 GetDen 访问器方法未声明为“const”,因此无法在 operator+ 中针对 const Fractions 调用它们。

    【讨论】:

      【解决方案3】:

      第一个问题,你为什么让函数首先返回一个“const Fraction”?这对您的代码的使用方式施加了任意限制。很明显,您的 Fraction 类基本上已经是隐式的 const。不需要这样做。

      但是,您的成员函数是非常量的。也就是说,它们不会告诉编译器您不会尝试更改类本身的状态。对于所有不改变状态的成员函数,请在成员函数声明的末尾加上关键字“const”。

      【讨论】:

      • 这只是一个示例任务。除了按照我的讲师的指示练习并理解正在发生的事情之外,它没有任何实际目的。我不能告诉你为什么我要返回一个 const 分数。提供了这个定义,我将提供它的主体。
      • @Lee 好的,这是有道理的。我会说你的教练正在鼓励糟糕的编码实践。只要您了解原因或认识到从函数返回类似的“const 对象”通常不是灵活性的最佳设计,您就会在您的职业生涯中做得很好。
      【解决方案4】:

      你的 getter 不是 const:

          int GetNum() const { return _num; }
          int GetDen() const { return _den; }
               ///    ^^^^^^^^
      

      您实际上并不需要这些吸气剂。我个人会把它们扔掉。
      注意:一个类是它自己的朋友,因此可以访问另一个实例的成员。

      const Fraction Fraction::operator+ (const Fraction &rhs) const
      {
          return Fraction(_num * rhs._den+ (rhs._num * _den), _den * rhs._den);
      }
      

      其他说明:

      • 同时将 void 设置为参数不是一个好主意(这是 C 风格)。
      • const int 真的没有意义,只是让它返回 int。
      • 请不要使用下划线作为第一个字符。它是合法的,但如果您不小心并且不了解有关下划线的所有规则,则很容易出错。

      【讨论】:

      • 有人告诉我,对私人成员使用下划线是一种很好的做法。
      • @Lee:这不是很好的做法,它只是个人风格。我认为它绝对不会给您带来任何好处,并且您会面临一大堆其他潜在问题。现在我已经看到前缀'm_'至少你可以告诉它是一个成员。 你知道在标识符中使用下划线的规则吗?
      • 我的讲师使用 m_,直到现在我才明白这是什么意思,感谢您指出这一点。恐怕我对下划线规则一无所知。
      • @Lee:这就是为什么你不应该在标识符的开头使用它们的原因。规则非常模糊:Summary here.
      【解决方案5】:
      const int GetDen(void) { return _den; }
      

      应该(或可能)是

      int GetDen(void) const { return _den; }
      

      第一个返回一个常量副本。复制返回意味着将生成副本并将其作为临时对象提供给调用者函数,因此是 const(“只读”)对象。因此,按副本返回会使副本成为只读的。

      即使 Fraction 对象是 const,第二个也使您的函数可以调用 - 它是一个“只读”可访问函数(您可能会说)。这可能是你想写的,如果没有,那也比没有 const 好。

      顺便说一句,参数中的 void 在 C++ 中没有用,你可以避免输入它,直接说 int GetNum() const{ return _num; }

      另一个细节:以下划线字符开头的名称由标准保留用于标准实现。使用它们并不是很危险,但你永远不知道。如果要保留它们,至少将所有代码封装在命名空间中。

      【讨论】:

      • 我了解参数问题。老实说,Visual Studio 为我添加了 (void),所以我认为它很有用。就我自己而言,从头开始,我通常会将它们留空。感谢您提供有用的信息:)
      • VS?奇怪,它甚至不应该为你生成代码。您使用的是 Visual Assist 还是某些扩展程序?
      • 我正在使用 VS 2010 - Visual C++。当我向我的项目“添加”一个类时。我知道它很懒,但它会为你添加头文件和 cpp 文件并填写最低定义。
      猜你喜欢
      • 2021-12-26
      • 2011-06-23
      • 1970-01-01
      • 1970-01-01
      • 2020-06-20
      • 2019-01-08
      • 2020-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多