c++ postfix / prefix operator overload as non-member function
Asked Answered
F

1

3

I am writing my own array class as an exercise. Since, I read non-member functions are actually better in some ways than member functions. (Scott Meyers)

I am trying to write as many operator overloads as non-member functions as possible. The operator overloads + , - all work out fine as non-member functions.

my_array operator+(const my_array & left, const my_array & right);
my_array operator-(const my_array & operand);
my_array & operator++();  // prefix
my_array   operator++(int); //postfix, compiler puts a 0

However, the prefix/postfix operators as non-member functions give issues (they work fine if I use scope resolution and make them member functions)

I understand that not every operator overload can be member functions. But , I am having trouble as to why these two cannot be non-member functions. The error I get is:

: 'my_array& operator++()' must have an argument of class or enumerated type

Which basically can be solved if I make them member functions and allow a *this array obj to be passed along in the following format.

(*this).operator++();

But the whole thing is, I do not want to make them member functions in first place! So, is it that the pre/post fix operators cannot/should not be implemented as non-member function?

The reasoning I came up with is that, since postfix/prefix is unary operator they only have one argument (usually a *this). So, if I want the compiler to provide the *this pointer implicitly and call the overloads, they must be implemented as a member-function.

Is My reasoning correct? If not how do I implement this as a non-member function? Thanks for providing me with some insight.

Forayer answered 13/9, 2013 at 15:3 Comment(2)
What do your ++ operators do? Call ++ on each element?Enchanting
<br>yap, this is just to exercise writing code.<br/> <pre> my_array& operator++( my_array & operand) //prefix { for (int i = 0; i < operand.get_number_of_elements(); ++i) { ++(operand[i]); } return operand; } my_array operator++(my_array &operand, int) //postfix { my_array result(operand); ++(operand); return result; }Forayer
R
4

Perhaps I misunderstood, but if you're struggling with proper declaration of both operators, you can still do this with free operators like members. You do, however, need to pass the object as the first parameter by-reference. You're correct that as member functions they get their object for free via this. As a free function, you need to push it yourself.

#include <iostream>

struct my_array
{
    // your members here.
};

my_array& operator ++(my_array& obj)
{
    // access to members is through obj.member
    std::cout << "++obj called." << std::endl;
    return obj;
}

my_array operator ++(my_array& obj, int)
{
    my_array prev = obj;

    // modify obj, but return the previous state.        
    std::cout << "obj++ called." << std::endl;

    return prev;
}

int main(int argc, char *argv[])
{
    my_array obj;
    ++obj;
    obj++;
    return 0;
}

Output

++obj called.
obj++ called.
Richards answered 13/9, 2013 at 15:15 Comment(13)
that does it.. I was having trouble with how the postfix signature would work in this case. my_array& operator ++(my_array& obj, int) answers my question. Some of my reasonings were wrongForayer
@Forayer Actually, the postfix one given in the answer is not the usual one. It should return by value, because it must return the value before the increment.Gigahertz
@Angew I concur. It was the param list he was after, but I will update the answer accordingly. Thanks for the eagle-eye.Richards
@Richards Actually, I spotted it from the review queue, as somebody edited that in, but they changed it to const my_array, which I had to reject as invalid. We don't want to return by const value now that move semantics exist.Gigahertz
@Angew No kidding. I was in the review queue? Ah. someone's edit was in the queue. Much appreciated that you brought it here. I've no problem fixing something that isn't correct, to be sure. (still too early here, not enough caffeine yet =P).Richards
@Angew, "We don't want to return by const value now that move semantics exist" Really? Surely the return value of a postfix operator is a temporary that you do not want to accidentally mutate.Enchanting
@AdamBurry But you most definitely want to be able to move from it. And even if you mutate it in antoher way, so what?Gigahertz
@Angew, ah, now I see the complaint. You should be able to move from a const object. Can you not? I thought const meant thread-safe, not bitwise immutable.Enchanting
@AdamBurry It means you cannot modify it. The move ctor/move assignment op would have to take const my_array&& as a parameter, and there's not much you can do through a const reference. You certainly can't assign to data members (such as stealing a pointer and setting it to nullptr).Gigahertz
@Angew Thanks for the edit, btw. damn spell-check on my Mac gets a little intrusive when I'm writing code on SO =P.Richards
@Angew, see: herbsutter.com/2013/01/01/video-you-dont-know-const-and-mutable and the discussion here: #14101160Enchanting
@AdamBurry I've seen Sutter's talk. But the language has its rules - you cannot modify an object through a const glvalue, except for the mutable members of an object of class type.Gigahertz
This point discussed here: #7139280Enchanting

© 2022 - 2024 — McMap. All rights reserved.