c++ operator overloading memory question

后端 未结 6 2038
挽巷
挽巷 2021-01-01 07:44

In c++ you can create new instances of a class on both the heap and stack. When overloading an operator are you able to instantiate on the stack in a way that makes sense?

6条回答
  •  星月不相逢
    2021-01-01 08:08

    You've already had a few good answers. Here's a few more points I'd like to add to them:

    • You should try to avoid copying Point objects. Since they are bigger than built-in types (from your code I assume they consist of two built-ins), copying them is, on most architectures, more expensive than passing them around per reference. That changes your operator to: Point Point::operator+ (Point&) (Note that you have to copy the result, as there's no place it can be stored persistently so you can pass around a reference to it.)
    • However, to make the compiler check you didn't screw it up and accidentally modified the operator's argument, you pass it per const reference: Point Point::operator+ (const Point&).
    • Since operator+() (other than, e.g., operator+=()) doesn't change its left argument either, you should make the compiler check that, too. For a binary operator that is a member function, the left argument is what the this pointer points to. To make this a constant in a member function, you have to inject a const at the end of the member function's signature. That makes it: Point Point::operator+ (const Point&) const. Now your operator is what's usually called const-correct.
    • Usually, when you provide operator+() for your type, people will expect operator+=() to also be present, so usually you should implement both. Since they behave quite similar, to not to be redundant you should implement one on top of the other. The easiest and most efficient (and therefor more or less canonical) way to do this is to implement + on top of +=. That makes operator+() quite easy to write -- and what's even more important: basically it looks the same for every type you implement it for:

    Since operator+() became quite trivial, you would probably want to inline it. This would then be the resulting code so far:

     inline Point Point::operator+ (const Point& rhs) const
     {
        Point result(this);
        result += a;
        return result;
     }
    

    These are a few basic syntactic and semantic peculiarities which (hopefully) all reading this will agree to. Now here comes a rule of thumb that I use for my code and which I find very helpful, but which probably not everyone will agree to:

    • Binary operators that treat both of their arguments equally (which usually means they don't change either of them), should be implemented as free functions, binary operators that treat their left argument (usually: that change it) should be implemented as member functions.

    The reason for the latter (take operator+=() as an example) is rather straight-forward: In order to change it, they might need to have access to the left argument's innards. And changing class object's innards is best done through member functions.

    The reasons for the former are not as simple. Among other things, Scott Meyers had an excellent article explaining that, contrary to popular belief, using non-member functions often actually increase encapsulation. But then there's also the fact that for the this argument of member functions, some rules (implicit conversions, dynamic dispatch etc.) differ from those for the other arguments. Since you want both arguments to be treated equally, it might be surprising under some circumstances to have different rules apply to the left-hand side.

    The code then looks like this:

     inline Point operator+ (const Point& lhs, const Point& rhs) const
     {
        Point result(lhs);
        result += rhs;
        return result;
     }
    

    To me, this is the ultimate canonical form of it which I write down in my code without much thinking about it, no matter what type it is.

    Implementing operator+=() is left as an exercise to the reader. :)

提交回复
热议问题