views:

86

answers:

3

I have a class like this:

class A {
    ...private functions, variables, etc...
public:
    ...some public functions and variables...

    A operator * (double);
    A operator / (double);
    A operator * (A);
    ...and lots of other operators
}

However, I want to also be able to do stuff like 2 * A instead of only being allowed to do A * 2, and so I would need functions like these outside of the class:

A operator * (double, A);
A operator / (double, A);
...etc...

Should I put all these operators outside of the class for consistency, or should I keep half inside and half outside?

+2  A: 

IMHO, the concern shouldn't be with stylistic consistency, but with encapsulation consistency; generally if a function does not need access to private members, it should not be part of the class. This is not a hard an fast rule, see arguments for it here.

So if your operators do not require private access, put them all outside. Otherwise, they will all have to be inside like so:

class A {
    ...
public:
    ...
    A operator * (double);
    A operator / (double);
    friend A operator * (double, A);
    friend A operator / (double, A);
    ...
};
academicRobot
Does using getters and setters count as requiring private access?
wrongusername
How would you make getter and setters free-functions? :) You'd need a getter and setter that has private access anyway. (Yes.)
GMan
@wrongusername - Anything that can be accomplished using the public class interface (including getters and setters), would not be considered to require private member access. I'd be careful though, comprehensive getters and setters work against encapsulation.
academicRobot
@GMan - I think w.u.n. means implementing operators on top of getters/setters.
academicRobot
+1  A: 

So what you are saying is that because you must put some operators (the ones that don't have A as the first param) outside the class, maybe you should put them all there so people know where to find them? I don't think so. I expect to find operators inside the class if at all possible. Certainly put the "outside" ones in the same file, that will help. And if the outside ones need access to private member variables, then adding the friend lines is a huge hint to look elsewhere in the file for those operators.

Would I go so far as to include the friend lines even if my implementation of the operators could actually be done with public getters and setters? I think I would. I think of those operators as really being part of the class. It's just that the language syntax requires them to be free functions. So generally I use friend and I write them as though they were member functions, not using getters and setters. It's a pleasant side effect that the resulting need for friend statements will cause them all to be listed in the definition of the class.

Kate Gregory
Just one more question: so if I have an operator function that does not require getters or setters, I would place it inside the class as a friend? btw, thanks for your informative answer!
wrongusername
Adding a line with the word `friend` in it isn't putting the operator in the class. The operator is still outside the class. It's putting a rule that says the operator can use private members directly. It has the side effect of announcing, inside the class, that the operator exists. I find the side effect helpful enough to add the `friend` lines even if technically the operators don't need that access.
Kate Gregory
+2  A: 

From your replies to comments in the question it seems that you have an implicit conversion from double to A in your class. something like:

class A
{
    // ...
public:
    A(double);

    // ...
};

In this case you can simply define a free function for each operator of the form:

A operator*( const A&, const A& );

and it will be used if either side is an A object and the other side is implicitly convertible to an A. For this reason it is often preferable to make symmetric binary operators free functions.

Frequently it can be easier to implement binary * in terms of the assignment version *=. In this case I would make the assignment version a member function and define * as something like:

A operator*( const A& l, const A& r )
{
    A result(l);
    result += r;
    return result;
}

Otherwise as operator* is plainly part of your class interface I would have no problem with making it a friend if required.

Charles Bailey
Thank you! What about making it a member of the class?
wrongusername
@wrongusername: You mean `op*` ? There's no advantage and you wouldn't get implicit conversion of the left hand side, so why would you want to?
Charles Bailey
@Charles Bailey--my original question was whether I should make my operators members if I'm going to make them friends anywaysBut now that you mention it, wouldn't I want to do some stuff with Terms like `d = (a * b) + c`?
wrongusername
@wrongusername: The two are mutually exclusive. A member function can't be a friend (of the class of which it is a member) so, for each operator, either it's a member function or it's a free function which may also be a friend. My answer is that for symmetric binary operators such as `*` you should prefer making the operators free functions and friends if necessary; assignment operators must be member functions. Sorry if this wasn't totally clear.
Charles Bailey
@Charles Bailey--Thanks, I understand what you meant now! :)
wrongusername