2

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.

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
thassan
  • 391
  • 3
  • 15
  • What do your ++ operators do? Call ++ on each element? – Adam Burry Sep 13 '13 at 16:01
  • yap, this is just to exercise writing code.
         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;
           }
    – thassan Sep 13 '13 at 16:27

1 Answers1

3

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.
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • 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 wrong – thassan Sep 13 '13 at 15:33
  • @thassan 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. – Angew is no longer proud of SO Sep 13 '13 at 15:34
  • @Angew I concur. It was the param list he was after, but I will update the answer accordingly. Thanks for the eagle-eye. – WhozCraig Sep 13 '13 at 15:35
  • @WhozCraig 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. – Angew is no longer proud of SO Sep 13 '13 at 15:35
  • @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). – WhozCraig Sep 13 '13 at 15:38
  • @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. – Adam Burry Sep 13 '13 at 15:39
  • 1
    @AdamBurry But you most definitely want to be able to move from it. And even if you mutate it in antoher way, so what? – Angew is no longer proud of SO Sep 13 '13 at 15:40
  • @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. – Adam Burry Sep 13 '13 at 15:42
  • 1
    @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`). – Angew is no longer proud of SO Sep 13 '13 at 15:44
  • @Angew Thanks for the edit, btw. damn spell-check on my Mac gets a little intrusive when I'm writing code on SO =P. – WhozCraig Sep 13 '13 at 15:50
  • @Angew, see: http://herbsutter.com/2013/01/01/video-you-dont-know-const-and-mutable/ and the discussion here: http://stackoverflow.com/questions/14100660/xxconst-x-const-move-constructor – Adam Burry Sep 13 '13 at 15:53
  • @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. – Angew is no longer proud of SO Sep 13 '13 at 15:58
  • This point discussed here: http://stackoverflow.com/questions/7138780/move-semantics-returning-const-values – Adam Burry Sep 13 '13 at 18:30