views:

305

answers:

4

Hello!

I have the following question:

Assume base class A with method:

A& operator+(A& a) {...}

I also have a derived class B which overloads (or at least it should so) this method:

A& operator+(B& b) {...}

The problem is that if i want to call something like: b + a (where b is of type B and a of type A) i get a compile error. (error C2679: binary '+' : no operator found which takes a right-hand operand of type 'A' (or there is no acceptable conversion)).

Shouldnt that call the base class method? (it looks like it overrides the method..) If not, why? Is there a way to fix this (dont tell me to overload the method in B with A&)

Sorry i dont give examples in formated text, but i dont know how to format it.

Thanks in advance!

PS Im using Visual studio 2010 beta.

+2  A: 
Nikolai N Fetissov
Can you better explain what you mean?
George B.
Edit: ok got it, but that doesnt help me
George B.
Thanks but i wont really use it with the real semantics of +, so its ok!
George B.
A: 

Couple of things come to mind. First, you would generally want to make the operator + "virtual". Then, the derived operator + taking a reference to B would be an override due to co-variance, instead of hiding the base class implementation, which is what is happening here.

That said, I suspect (but can't say for certain without compiling a test project) that that would actually solve your problem. That's because the standard answer for binary operators is to use static methods that take two parameters on the class. The C++ STL uses this technique extensively, and I don't know of a reason to attempt to implement binary operators as instance methods, virtual or not. It's just too confusing, with no real up-side.

David Gladfelter
Correction: I think as Nikolai said, they're actually implemented as free methods. Take a look at the << and >> operator overloads in the STL for the stream classes for examples.
David Gladfelter
2nd Correction: Ignore that 1st paragraph. I forgot that covariance in C++ is only for return types.
David Gladfelter
+3  A: 

The problem is called hiding - a member function in a derived class hides functions with the same name in the base class. In this case you can't access A::operator+(A&) because it's being hidden by B::operator+. The way to fix this is to define B::operator+(A&), and possibly have it call the base class function.

Edit: There's a section in the C++ FAQ Lite that goes into more detail about this problem and offers another possible solution, namely the using keyword.

Mark Ransom
Well, that makes sense, even if that should not happen in my opinion.I will do as you said and redefine it in the derived class.Thanks
George B.
I never liked it either, but that's the way C++ works for better or for worse. It's one of those obscure corners of the language that bites everyone eventually. The compiler writers must have had a very good reason for wanting it that way.
Mark Ransom
+2  A: 

No, it won't call the base class function. Class B has an operator+, it doesn't take the correct parameter, end of story.

You can define operator+ as a free function, not in any class. Perhaps a friend, if it needs to access private data:

A operator+(const A &lhs, const A &rhs) { ... }
B operator+(const B &lhs, const B &rhs) { ... }

Then b + a will call the first operator, as will a + b. b + b will call the second.

Alternatively, you could "un-hide" the base class implementation, by putting this in class B:

using A::operator+;

it's probably best not to, though. Most operators work better as free functions, because then you get automatic conversions on both operands. C++ never performs conversions on the LHS of a member function call.

Btw, operator+ almost certainly should return by value, not by reference, since an automatic (stack) variable no longer exists once the function returns. So the caller needs to be passed a copy of the result, not a reference to it. For this reason operator+ and inheritance aren't a great mix, although it can probably work as long as the caller knows what they're doing.

Steve Jessop
Dont worry, i wouldnt do it if i dont needed to. (im returning a reference to a new allocated object).Thanks but i have to use class methods to achieve what i want.
George B.
If you're returning a reference to a newly allocated object, it is almost certainly better to write a function rather than call `operator+`, because you cannot match the usual semantics for operator+. With your code, the following all leak memory: `A c = a + b;`, `a = a + b;`, `A `. An overloaded operator+ should "behave like" addition, otherwise why overload?
Steve Jessop
Could you expand on why you have to use a member function? As far as I know, there is nothing in C++ that a member function can do, that a free function can't, other than the obvious shorthand of `this` being assumed instead of specifying an object.
Steve Jessop
I see why you need operators, I don't see why they need to be member functions. If you're going to somehow implement a garbage collector, then you can avoid the memory leaks.
Steve Jessop
Well you are right, maybe its not necessary, thats true. But what if i want to have access to variables and still use encapsulation?Btw im new to c++ and thats my first project there. So forgive me if im wrong somewhere.
George B.
+1 for the clear answer. For sure this is the way to go. I don't see how virtual functions would do any good, and for sure duplicating the code found in `B` isn't good either.
Johannes Schaub - litb
@George. Make the free function a friend of the class, and declare/define it in the same header/source file. This doesn't break encapsulation, because the operator is part of the class's public interface. Whether the code for it happens to be within the curly braces of the class definition is irrelevant, although actually there is a syntax to do that if it makes you feel better ;-). If you can't bear to use friend, then write a free operator which calls a public "add" member function. Then you'll have the symmetrical conversion handling which you can't get from a member function operator.
Steve Jessop
The syntax, btw, is `class A { public: friend A operator+(const A `
Steve Jessop