C++:重载数学运算符

发布于 2024-09-06 11:45:09 字数 811 浏览 5 评论 0原文

我希望重载加法运算符,并让它添加同一类的两个对象。当我在头文件的类声明中声明这个“operator+”原型函数时,我将两个对象作为参数传递。我收到编译器错误,指出“二进制‘运算符 +’有太多参数”。我在网上寻找答案,发现在编译出来的头文件中的类声明之外声明了一个内联函数。我想知道我做错了什么或者我是否在这里遗漏了一些东西。这是我在头文件中使用的代码。

class Person
{
private:
    int age;
    double weight;
public:
    Person::Person();                           //default constructor       
    Person::~Person();                           //default desctructor
    Person operator+(Person r, Person i);
};

编译时会出现我上面提到的错误。下面是编译良好的代码。

class Person
{
private:
    int age;
    double weight;
public:
    Person::Person();                           //default constructor       
    Person::~Person();                           //default desctructor
};
inline Person operator+(Person r, Person i)
{
return Person(0,0); 
}

I am looking to overload, let's say, the addition operator and have it add two objects of the same class. When I declare this "operator+" prototype function in the class declaration in the header file, I pass in both objects as parameters. I get a compiler error saying that "binary 'operator +' has too many parameters". I was searching around for an answer online and found out that declaring an inline function just outside the class declaration in the header file compiled out. I'm wondering what I was doing wrong or if I'm missing something here. Here is the code I am using in the header file.

class Person
{
private:
    int age;
    double weight;
public:
    Person::Person();                           //default constructor       
    Person::~Person();                           //default desctructor
    Person operator+(Person r, Person i);
};

This compiles with the error I mentioned above. Below is the code that compiles fine.

class Person
{
private:
    int age;
    double weight;
public:
    Person::Person();                           //default constructor       
    Person::~Person();                           //default desctructor
};
inline Person operator+(Person r, Person i)
{
return Person(0,0); 
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

下雨或天晴 2024-09-13 11:45:09

如果您将 oparator+ 声明为实例函数,则第一个参数将作为 this 对象传递,因此您只需要一个参数。阅读本文以获取更多信息,特别是尝试理解 const 概念:

http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html

中建议的最佳方法引用的文章是:

class Person
{
    ...
    Person &operator+=(const Person &i);
    const Person operator+(const Person &i) const;
    ...
};

Person &Person::operator+=(const Person &i) {
    ...   // Do the compound assignment work.
    return *this;
}

const Person Person::operator+(const Person &i) const {    
    Person result = *this;     // Make a copy of myself.  Same as MyClass result(*this);
    result += i;            // Use += to add other to the copy.
    return result;              // All done!
}

如果您决定使用 const 版本,请记住您将只能在 thisi 上调用 const 方法参考文献。这是首选方式。

我引用的文章详细解释了首先重载 += 然后使用 += 定义 + 的想法。这是一个好主意,因为 += 运算符必须单独重载。

另外 - David Rodríguez 建议将 operator+ 实现为自由函数,而不管 += 是否存在。

If you declare oparator+ as an instance function then the first argument is being passed as this object and thus you need only one more argument. Read this for more info, in particular try to understand the const concept:

http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html

The best approach as advised in the referenced artice is:

class Person
{
    ...
    Person &operator+=(const Person &i);
    const Person operator+(const Person &i) const;
    ...
};

Person &Person::operator+=(const Person &i) {
    ...   // Do the compound assignment work.
    return *this;
}

const Person Person::operator+(const Person &i) const {    
    Person result = *this;     // Make a copy of myself.  Same as MyClass result(*this);
    result += i;            // Use += to add other to the copy.
    return result;              // All done!
}

if you decide to use const version remember that you will only be able to call const methods on this and i references. This is the preferred way.

The article I referenced to explains the idea of overloading += first and then defining + using += in more details. This is a good idea since += operator must be separately overloaded.

Additionally - David Rodríguez suggests operator+ to be implemented as a free function regardless of the presence of += .

寻找我们的幸福 2024-09-13 11:45:09

每个成员函数都有一个隐式的第一个参数:this。对于运营商来说也是如此。因此,如果你想让 operator+() 成为一个成员,它必须只接受一个参数,即右操作数,因为左操作数已经是 this 了。

但是,对于可以是成员函数或自由函数的二元运算符,我的经验法则是使它们成为对称处理其参数的自由函数(operator+() 不会改变以下任何一个)其操作数),并将它们设为不更改的成员函数(operator+=() 更改其左操作数,但不更改其右操作数)。
此外,对于所有算术运算符,有一个很好的模式可以根据它们的组合赋值版本来实现它们。也就是说,operator+() 将基于 operator+=()- 基于 -= 等。
除此之外,您不想不必要地复制类对象,但通常希望它们按 const 引用传递。

基于此,我的 operator+ 规范版本将是:

class Person
{
public:
    Person& operator+=(const Person& i)
    {
      // whatever
      return *this;
    }
};

inline Person operator+(Person lhs, const Person& rhs)
{
  lhs += rhs; // note: lhs passed per copy
  return lhs;
}

但是。关于运算符重载的最重要的经验法则可能是:< strong>不要这样做。这可能听起来很矛盾,但大多数情况下命名函数比运算符要好得多,因为后者使代码的可读性低于普通函数。在编写代码时,可读性应该是最重要的方面。 除非运算符在应用程序域中具有明确且无可争议的含义,否则不要为类重载它
在您的示例中,运算符 + 应用于两个人肯定没有没有明确且无可争议的含义。在现实世界中添加到人意味着什么? (我能想到的第一个含义不会是一个人,而是一群人。:)
因此,除非为您的 Person 类重载此运算符是一项家庭作业,否则我强烈建议您不要这样做。 (如果这是一项作业,我会责怪老师找到这么糟糕的例子。)

Every member function has an implicit first argument: this. This is also true for operators. Therefor, if you want to make operator+() a member, it must only take one argument, the right operand, because the left operand already is this.

However, for binary operators that can be either a member function or a free function, my rule of thumb is to make those a free function which treat their arguments symmetrically (operator+() doesn't change either of its operands), and make those a member function which don't (operator+=() changes its left operand, but not its right).
Further, for all arithmetical operators, there's a nice pattern to implement them based on their combined assignment versions. That is, operator+() would be based on operator+=(), - based on -= etc.
Add to this that you don't want to needlessly copy class objects, but usually want them to be passed per const reference.

Based on this, my canonical versions of operator+ would be:

class Person
{
public:
    Person& operator+=(const Person& i)
    {
      // whatever
      return *this;
    }
};

inline Person operator+(Person lhs, const Person& rhs)
{
  lhs += rhs; // note: lhs passed per copy
  return lhs;
}

However. What's probably the most important rule of thumb regarding operator overloading is this: Don't do it. This might sound paradoxical, but most often named functions are a lot better than operators, because the latter make the code less readable than normal functions would. And when writing code, readability should be the most important aspect. Unless an operators has a clear and undisputed meaning in the application domain, don't overload it for a class.
In your example there certainly is no clean and undisputed meaning of operator + applied to two persons. What does it mean in the real world to add to persons? (The first meaning I could think of wouldn't have a single person as a result, but an array of persons.:))
So, unless overloading this operator for your Person class is a homework assignment, I would strongly advice against it. (And if it is an assignment, I'd blame the teacher for finding such a bad example.)

浮萍、无处依 2024-09-13 11:45:09

这是一个在类中工作 += 的示例。

Vector3D& operator+=( const Vector3D& other ) {
        x+=other.x;
        y+=other.y;
        z+=other.z;
        return *this;
    }

Here is an example for a working += in a class.

Vector3D& operator+=( const Vector3D& other ) {
        x+=other.x;
        y+=other.y;
        z+=other.z;
        return *this;
    }
冰雪梦之恋 2024-09-13 11:45:09

根据我的阅读,最佳实践是将operator+声明为友元函数而不是成员函数。

cplusplus.com 对这个问题进行了全面的讨论:

二元运算符是朋友 - 为什么?< /a>

Meyers 在他的书《Effective C++ IIRC》中也对此进行了讨论。

引用geustgulkan的评论

对于任何给定的二元运算符,它
执行以下操作的左手对象
操作。

假设我们有一个 ClassX 类,其中有
+ 运算符的重载
整数。那么如果我们创建一个对象
这个类(称之为 objx),然后我们
可以说 objx + 2. objx 将携带
退出操作并返回
ClassX 的结果对象。

但是如果我们说 2 + objx 会发生什么?
结果应该与 2 + 相同
objx - 但整数不是类
当然数字文字不是
- 所以 2+objx 是不可能直接实现的。

如果我们必须设计的话会很痛苦
我们的代码确保我们始终拥有
左侧的 ClassX 对象
每当我们想要时,就在 + 的一侧
添加一个 int 到它。

这是我们使用好友重载的地方
对于 ClassX 的运算符+。

class ClassX
{

    friend ClassX operator+(ClassX objx, int i);
    friend ClassX operator+(int i, ClassX objx);
};

所以你可能想要的是:

class Person
{
private:
    int age;
    double weight;
public:
    Person::Person();                           //default constructor       
    Person::~Person();                           //default desctructor
    friend Person operator+(const Person &rhs, const Person &lhs);
};

Person operator+(const Person &lhs, const Person &rhs) {
     // do whatever constitutes addition here
     Person temp = lhs;
     temp.weight += rhs.weight;
     return temp;  // return copy of temp
}

From what I've read the best practice is to declare operator+ as a friend function and not as a member function.

There's a whole discussion of this issue over at cplusplus.com:

Binary operators as friends - why?

Meyers also discusses it in his book Effective C++ IIRC.

Quoting from the comment of geustgulkan:

For any given binary operator, it the
left hand object that carries out the
operation.

Say we have a class ClassX which has
an overload for the + operator for
integers. Then if we create an object
of thet class (call it objx), then we
can say objx + 2. objx will will carry
out the operation and return the
result object of ClassX.

But what happens if we say 2 + objx ?
The result should be the same as 2 +
objx - BUT integers are not classes
and certainly numeric literals are not
- so 2+objx is not possible directly.

It would be a pain if we had to design
our code to make sure we always has
ojbjects of ClassX on the left hand
side of the + whenever we wanted to
add an int to it.

This is where we use friend overloads
for operator+ for ClassX.

class ClassX
{

    friend ClassX operator+(ClassX objx, int i);
    friend ClassX operator+(int i, ClassX objx);
};

So what you probably want is:

class Person
{
private:
    int age;
    double weight;
public:
    Person::Person();                           //default constructor       
    Person::~Person();                           //default desctructor
    friend Person operator+(const Person &rhs, const Person &lhs);
};

Person operator+(const Person &lhs, const Person &rhs) {
     // do whatever constitutes addition here
     Person temp = lhs;
     temp.weight += rhs.weight;
     return temp;  // return copy of temp
}
鱼忆七猫命九 2024-09-13 11:45:09

我只有一个建议:使用 Boost.Operators。

class Person: boost::addable<Person>      // yes private inheritance
{
public:
  Person& operator+=(Person const& rhs);

private:
};

据我所知,有两个优点:

  • 无需编写样板代码,因此没有机会出错;)
  • 为了提供清晰的界面,addable 几乎是不言自明的

Boost.Operators 提供了一个参考表,其中为每个行为列出了应定义的所需运算符以及将自动生成的运算符。

保持界面紧凑并将一些文档直接注入代码中非常方便。

I only have one advise: use Boost.Operators.

class Person: boost::addable<Person>      // yes private inheritance
{
public:
  Person& operator+=(Person const& rhs);

private:
};

There are 2 advantages as far as I can see:

  • No need to write boiler-plate code, and thus no chance to get it wrong ;)
  • Make for a clear interface, addable is pretty much self-explanatory

Boost.Operators provides a reference table, which for each behavior lists the required operators that should be defined and those that will be generated automatically.

It's very handy to keep the interface compact and to inject some documentation right into the code.

神也荒唐 2024-09-13 11:45:09

似乎您进行了成员运算符+声明,无意引用任何人员实例数据:成员运算符与任何成员方法一样,接受调用它的实例作为参数。

如果由于某种原因您需要使其成为成员(例如,访问私有状态),您可以将其声明为静态。

Seems you made the member operator+ declaration with no intent to reference any Person-instance data: the member operator, as any member method, accepts the instance on which it is invoked as an argument.

If for some reason you need to make it a member (e.g., access to private state), you can declare it static.

迷迭香的记忆 2024-09-13 11:45:09

我同意agsamek和履行机构的论点。我添加了一些额外的注意事项,

  1. 因为您可以看到您的班级人员
    没有任何带有 2 的构造函数
    参数,这是一个错误(但是
    编译器尚未发出信号)
  2. 通常当您重载一个数学运算符时,您还需要重载“operator=”和构造函数;
  3. 如果你想超载加号
    有 2 个参数的运算符你不能
    使用实例成员,但您必须
    使用一个函数。我避免声明
    朋友功能因为你打破
    该类的封装(它将
    更难维护)。它是
    更好地实现一些“访问器
    方法”来获取对象的内部
    价值观;
  4. 在某些编译器中,内联方法需要
    中的声明和定义
    相同的地方(通常在 .h 文件中),所以更少
    可操作的。此外,扩展
    该代码的一部分位于编译器处
    酌情权。

接下来按照我的解决方案来解决你的问题:

class Person
{
private:
    int age;
    double weight;
public:
    Person(){}                           //default constructor       
    Person(int a, double w) : age(a), weight(w) {}
    ~Person(){}                           //default desctructor

    int getAge() const { return age; }
    double getWeight() const { return weight; }

    const Person & operator =(const Person & rha) {
        age = rha.age; weight = rha.weight; return *this;
    }
};

Person operator +(const Person & lha, const Person & rha)
{
    return Person(lha.getAge() + rha.getAge(), rha.getWeight() + lha.getAge());
}

int _tmain(int argc, _TCHAR* argv[])
{
    Person p1(30,75);
    Person p2(40,80);

    Person sumOfPis = p1 + p2;  // <-- Without "operator =" this statement will use the default copy constructor

    return 0;
}

I agree with argumentations of agsamek and sbi. I add some extra considerations

  1. as you can see your class Person
    doesn't have any costructor with 2
    arguments and that's an error (but
    not yet signaled by compiler)
  2. ofen when you overload one math operator you need also to overload the "operator=" and the constructor;
  3. if you want to overload the plus
    operator with 2 arguments you can't
    use an instance member but you must
    use a function. I avoid to declare
    friend functions because you break
    encapsulation of that class (it will
    be more difficult to maintain). It's
    better to implement some "accessor
    methods" to get object's internal
    values;
  4. in some compilers, an inline method needs
    declaration and definition in the
    same place (normally in .h file) so in less
    manutenable. Moreover the expansion
    of that code is at compiler
    discrection.

Next follow my solution to your question:

class Person
{
private:
    int age;
    double weight;
public:
    Person(){}                           //default constructor       
    Person(int a, double w) : age(a), weight(w) {}
    ~Person(){}                           //default desctructor

    int getAge() const { return age; }
    double getWeight() const { return weight; }

    const Person & operator =(const Person & rha) {
        age = rha.age; weight = rha.weight; return *this;
    }
};

Person operator +(const Person & lha, const Person & rha)
{
    return Person(lha.getAge() + rha.getAge(), rha.getWeight() + lha.getAge());
}

int _tmain(int argc, _TCHAR* argv[])
{
    Person p1(30,75);
    Person p2(40,80);

    Person sumOfPis = p1 + p2;  // <-- Without "operator =" this statement will use the default copy constructor

    return 0;
}
酷遇一生 2024-09-13 11:45:09
 class Person
  {
    private:
     int age;
     double weight;
    public:
      Person();                           //default constructor       
      ~Person();                           // destructor
      Person operator+(const Person &r); //overloaded operator as member function, so only one argument is required to be passed
 };

实现:

  Person Person::operator+(const Person &r)
  {
      Person x;
      x.age=this->age + r.age; // this refers to the object on which the function has been invoked, P1 in this case(see below)
      return x;
  }

当您重载二元运算符(在本例中为+)作为成员函数时,调用该运算符的对象将隐式传递给该函数,并且您只需要显式传递一个参数

因此您的主函数应该是这样的

 int main()
 {
    Person P1,P2;
    P2=P1+P2; //P1 is passed implicitly 

    //The above expression is equivalent to P2=P1.operator+(P2);
}
 class Person
  {
    private:
     int age;
     double weight;
    public:
      Person();                           //default constructor       
      ~Person();                           // destructor
      Person operator+(const Person &r); //overloaded operator as member function, so only one argument is required to be passed
 };

Implementation :

  Person Person::operator+(const Person &r)
  {
      Person x;
      x.age=this->age + r.age; // this refers to the object on which the function has been invoked, P1 in this case(see below)
      return x;
  }

When you overload a binary operator(+ in this case) as member function, the object on which the operator is invoked is passed implicitly to the function and you need to pass only one argument explicitly

Thus your main function should be like this

 int main()
 {
    Person P1,P2;
    P2=P1+P2; //P1 is passed implicitly 

    //The above expression is equivalent to P2=P1.operator+(P2);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文