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.
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.
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.
The problem is that you are defining the member operator, so when called as b + a it results in b.operator+( a ), which doesn't exist.
Accepted practice is to define free operators that themselves would call [virtual] members on the arguments.
Edit:Standard example of what I'm talking about is adapting a class hierarchy for output streaming:
class base
{
public:
virtual ~base();
virtual void print( std::ostream& ) const;
};
std::ostream& operator<<( std::ostream& out, const base& b )
{
b.print( out ); return out;
}
This doesn't really work for math operations since you want to return by [const] value, not reference, i.e. avoid nonsense like a + b = c;.
For example, addition of real and complex numbers is defined, but yields complex number as the result, so you cannot derive complex from real. The other way - maybe. But still you want to define exact operations interface:
const real operator+( const real&, const real& );
const complex operator+( const complex&, const complex& );
Hope this gives you enough to re-think your design :)
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.
Related
I can operate class+class (for example I can do date+date), but can anyone explain how can I do class+class+class please? C++ does not let me define an operator with 2 parameters.
That's because there is no such operator in general.
a + b + c is (a + b) + c. First a + b, then the results
of that added to c.
EDIT:
If the objects in question are extremely big, so that creating
the temporaries in an expression like a + b + c is too
expensive, you can google for template expressions; the basic
idea is that operator+ doesn't do anything but return an
expression node, which can be evaluated later, as part of the
full expression.
By making them friends of the class, you would make sure they are binary operators, and define them separately, like so:
class someclass
{
int a;
public:
someclass();
...
friend someclass operator+(const someclass & lhs, const someclass & rhs);
};
someclass operator+(const someclass &lhs, const someclass &rhs)
{
someclass a = lhs;
a.a = a.a + rhs.a;
return a;
}
you will, of course need to define a copy constructor (someclass(const someclass & old);) and the other functions of the class, but this method has always worked for me, and it was how I was taught in college.
There are two ways you can approach this. The normal way with operators is, you just create a normal two operand operator, and then chain the calls together. For example a + b + c + d => operator+(operator+(operator+(a + b), c), d).
Alternately, create your own named function or member that provides a multi-parameter version, using the name to accurately describe what it does.
I suggest reading http://www.cs.rit.edu/~mjh/docs/c++-faq/operator-overloading.html
To the best of my understanding you do not need 2 parameters here. Your overload needs to return an object which the result of your operation. In this case your example class+class+class can actually be written as class+(class+class) so that (class+class) is processed first and then the result of that is added to the third class.
You are allowed to use arithmetic operators with two parameters. For example:
//References are used here as arguments.
Cents operator+(const Cents &c1, const Cents &c2)
{
// use the Cents constructor and operator+(int, int)
return Cents(c1.m_nCents + c2.m_nCents);
}
(Source: http://www.learncpp.com/cpp-tutorial/92-overloading-the-arithmetic-operators/)
Note: you need to declare the operator "function" as friend in class definition if you need to use private members of your class in it.
If you then return a class type same with those given as arguments (objects or references of them as here), you can do class + class + class..., assuming that each operator+ call is between 2 arguments, and the result is added to the third one invoking again the operator+ "function" etc.
I came here to ask something I can't figure out on my own. I've been coding a little class that stores an array of 32 bits and can perform simple mathematic operations like +, -, / and *.
Suppose I have a class like:
class Binary_Class
{
char bin[32]; // 32 bits array to hold an unsigned binary number
void set_dec(int value){}; // setting the bin[32] value based on input value
// I have operator + and = to perform on objects of this class.
Binary_Class& operator= (const Binary_Class&);
const Binary_Class operator+ (const Binary_Class&);
}
Until now, no problem comes up if i declare 3 objects a,b,c of class Binary_Class, then set_dec to a and b, the statement c=a+b can be used (?)
However, I want to extend the class binary by using a new class
class Binary_Class_Extended: public Binary_Class
{
// weird functions
}
If I declare 3 objects a, b, c of class Binary_Class_Extended, am I still able to use c=a+b as the same before that?
In Netbean it says there's no operator= that match my c=a+b if all are of Binary_Class_Extended,
but if I declare c as Binary_Class that statement works. That means a+b returns a const Binary_Class as if the operator+ doesn't get carried to the new class.
Am I missing something or this is the way it is?
Of course, I can post the whole code because it's just an assignment but I think these infos are enough for now.
Update
class Binary_Class
{
char bin[32]; // 32 bits array to hold an unsigned binary number
void set_dec(int value){}; // setting the bin[32] value based on input value
//i have operator + and = to perform on objects of this class.
Binary_Class& operator= (const Binary_Class&);
const Binary_Class operator+ (const Binary_Class&) const;
}
class Binary_Class_Extended: public Binary_Class
{
// weird functions
}
When I try to have all objects of Binary_Class_Extended this error show up:
main.cpp:285: error: no match for 'operator=' in 'sd = ((Binary_Class*)(&sa))->Binary_Class::operator+(((const Binary_Class&)((const Binary_Class*)((Binary_Class*)(&sb)))))'
Binary_ET_Class sa,sb,sc;
sc=sa+sb //initialized sa and sb to non-null value;
The full source code I've been working on: https://pastebin.com/eiVz0f5p
Inherited functions retain their finger prints, so if the Binary_Class operator+ was inherited, it's return value would be ... ?
In general, inheritance and assignment ("value semantics") don't mix easily in C++. In your second case, the "a+b" would return an instance of the baseclass, unless you define a separator operator+ for the derived class. The result is then only assigned to the base-class part of "c", which is triggering the error. This is also sometimes call slicing/truncation. Note that the choice of the operator is at compile time, no virtual functions are called, so the static type has to match.
Don't mix value types and polymorphic types. If you really need to and you have a fixed and known hierarchy, you can use the "Handle-Body Idiom" to preserve derived information when assigning to the baseclass. This is not a beginner topic though.
I am currently writing a program that models various types of numbers and manages them polymorphically in a Set object (already written and tested). My inheritance relationship is this:
Multinumber (all virtual functions, virtual class)
inherited by Pairs, Complex, Rational
The subclasses all have mostly the same functions with different parameters.
The problem that I am running into is in functions like this:
Multinumber& Complex::operator=(const Multinumber &rhs)
{
imag=rhs.imag;
real=rhs.real;
return *this;
}
Because I am treating this polymorphically, my return types and parameters all have to be of type Multinumber, in order to override the base class's parameters. However, I am having a terrible time getting this to compile. I am getting a boatload of errors along the lines of:
error: 'const class Multinumber' has no member named 'imag'
which is true. Multinumber does not have an imag attribute or function. But how can I get the compiler to realize that the Multinumber& rhs will always be Complex, or to treat it as such? Thank you for your help.
This is what my superclass looks like:
class Multinumber
{
public:
virtual Multinumber& operator+(Multinumber&);
virtual Multinumber& operator=(Multinumber&);
virtual bool operator==(Multinumber&);
virtual string object2string();
virtual Multinumber& makeobject(double, double)=0;
};
I think you'll have to cast. Try this:
Multinumber& Complex::operator=(const Multinumber &rhs){
const Complex & _rhs = dynamic_cast<const Complex &>(rhs);
imag=_rhs.imag;
real=_rhs.real;
return *this;
}
A signature such as :
Multinumber& Complex::operator=(const Multinumber &rhs)
means that any kind of Multinumber may be assigned to a Complex. Is that really something you want ? You have two options here :
Allow it and verify if the dynamic type of the parameter is indeed Complex (for example through a dynamic_cast). What will you do if it's not ? You will probably end up throwing an exception.
Forbid it as a whole by changing the signature to Multinumber& Complex::operator=(const Complex &rhs) : trying to assign a Rational to a Complex will fail to compile.
In the end, you're the only one who can really decide what better fits your needs, but from my point of view compile time errors are preferable to runtime errors.
On a side note, I think you gave the answer by asking "how can I get the compiler to realize that the Multinumber& rhs will always be Complex" : make it a Complex and it will never be anything else.
EDIT Now that we see that operator= is virtual in Multinumber, it seems you are indeed forced to stick with the initial signature and verify the dynamic type of the parameter in Complex::operator= (see Steve answer for this).
If you're SURE that Multinumber is always complex, you can simply cast your rhs to a Complex &.
However, that sounds like the wrong approach. Instead, why don't you simply write Complex& Complex::operator=(const Complex &rhs)? Your operator is not virtual, so there's no reason that it has to use the same types as your base class.
Give up. It can't be done. #beldaz is right that covariant arguments aren't allowed in C++ but misses the real point: it wouldn't help even if they were typesafe.
See my answer in:
C++ Abstract class can't have a method with a parameter of that class
The missing phrase here is covariant return types. In C++ an overridden method is allowed to return a derived (and therefore covariant) reference or pointer type. Hence
Complex& Complex::operator=(const Multinumber &rhs) is a valid overriding method of Multinumber& Multinumber::operator=(const Multinumber&)
Unfortunately I think you also want to have covariance on the parameter type. That's not allowed by the C++ standard, IFAIK. At this point you should probably consider whether you really want this polymorphism. It means that you must have a means to convert between types. Do you wish to support conversion between Pair and Complex types? If so, Steve's dynamic_cast approach seems the way to go. Otherwise you should remove methods such as operator= from Multinumber's overrideable methods and allow only the meaningful methods to be declared where they belong in the derived types.
Update
In response to further comments: Return type covariance only applies to references and pointers. Return by value doesn't work, since the storage requirements will differ for each type (unlike pointers). So Multinumber& operator+(Multinumber&) is a valid method that can be overridden, but it probably won't work as one would expect, since you can't return a reference to a newly created type, since it would be destroyed when the function completes. One way to get around this would be to replace that method with Multinumber& operator+=(const Multinumber&). For Complex you could then implement it as:
Complex& Complex::operator+=(const Multinumber &rhs){
const Complex & _rhs = dynamic_cast<const Complex &>(rhs);
imag+=_rhs.imag;
real+=_rhs.real;
return *this;
}
An alternative approach would be to deal completely with pointers, and make operator+ return a copy of a new pointer. But that's just plain awful, and I strongly recommend you keep away from such horrors - that's like C with structs before C++ came along. You could improve things with some form of polymorphic pimpl approach (note I haven't checked the following, it's just to give you an idea, and it certainly could be improved):
class Multinumber
{
public:
virtual Multinumber* operator+(const Multinumber&);
virtual Multinumber& operator=(const Multinumber&);
virtual bool operator==(const Multinumber&) const;
// etc.
};
class MultinumberOuter
{
std::unique_ptr<Multinumber> impl_;
public:
explicit MultinumberOuter(Multinumber* pimpl) : impl_(pimpl) {}
MultinumberOuter operator+(const MultinumberOuter& src) const {
return MultinumberOuter(impl_->operator+(*(src.impl_)));
}
MultinumberOuter& operator=(const MultinumberOuter& src) {
impl_->operator=(*(src.impl_));
return *this;
}
bool operator==(const MultinumberOuter& src) const {
return impl_->operator==(*(src.impl_));
}
// etc.
};
But, before going down this road, have a long think about whether such complexity is justified. Perhaps the level of polymorphism you're after is not warranted by the problem you've been set.
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?
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);
...
};
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.
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.
Forgive me my C++ is incredibly rusty. But I am trying to take some old code and recompile it under Visual C++ 2008. It was originally written for Visual C++ 6.0
The error I am getting is this:
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
Ok seems simple enough. But then I look at the offending line of code:
operator=(int i) {SetAsInt(i);};
And it appears the type IS declared. So what am I missing?
FOLLOW UP:
I took Micheals advice and added a return type of the function (the class), and added return this; to the end of each. Then I ran across this:
operator=(const CString& str);
There is no function body defined... what exactly does this mean?
You need to have the operator=() method return something (it would assume int if the diagnostic weren't an error, as the error message somewhat confusingly indicates).
Generally it would be a reference to the object the operator is working on so the assignments can be chained as in a normal assignment expression. Something like:
// where T is the class for this operator= implementation
T& operator=( int i) {
// ...
return *this;
}
As michael has said, operator= needs a return type, but this type can be void:
class A {
...
void operator = ( int i ) {
SetAsInt(i);
}
};
although this means you won't be able to "daisy-chain" assignments.
Regarding the follow-up, it's probably saying that assignment for the class is forbidden:
class B {
private:
void operator =( const B & );
};
Making the assignment op (and usually the copy ctor) private and then not implementing them means it is impossible to assign (or copy) class instances, which is desirable behaviour for most business -oriented classes.
For your second question, the declaration is likey being used to prevent copying the object.
From the C++ Reference Guide by Danny Kalev
Question: How Can I Prevent
Object-Copying?
Answer: Declare the copy constructor
and the assignment operator as private
members, without defining them. Any
statement that involves direct or
indirect copying of that class will
cause a compilation error. This
technique isn’t exactly the picture of
elegance, but in contemporary C++
there’s no other way to block copying
inexpensively.
Regarding your edit:
It simply means that the function has been declared, but not defined. The compiler knows it exists, so it is legal to call it. But it will generate a linker error, unless the compiler is actually able to find the body somewhere.
Typically, you define the function in a header file, and then in the .cpp file, you have something like
// Assuming the class it is a member of is called Foo
Foo& Foo::operator=(const CString& str) {
...
}
The only thing to note here is the Foo:: prefix. Because this definition is outside the class definition itself, we have to use this prefix to specify that the operator= we're defining belongs to the Foo class.
returning ANYTHING but an lval is typically wrong and is only used in very special situations
certainly returning a const reference precludes assignment chaining (a=(b=c)), and part of the point of operators is to make classes behave like built in types
Well, that's an assignment operator. It helps one define how other objects (both of the same and other types) are assigned to an instance of the class it is defined within.
The correct syntax is (assuming your class is called 'Object'):
const Object& operator=(const Object& other)
{
// copy members, one at a time.
this->member1 = other.member1;
return *this;
}
Notice the return type is constant. This is a to avoid semantically incorrect, syntactically correct statements such as:
Object A, B, C;
(A = B) = C;
If you define the return type as constant, the above code will not compile (reasonable enough, since it's really messed up) while leaving out the const will allow such bad code to compile, and of course someone will pull their hair trying to figure out what's wrong.
P.S. You might want to think it through: what would happen if you leave out the const from the return type and execute the (A = B) = C; code?
Regarding the follow-up question, the return type can be anything in this case. However, since most assignment operators return a reference to the class in which they are declared, it would be best to return just that, in order not to confuse the reader.
CString& operator=(const CString& str);
Presumably, this function is declared in the private section of the class. This is the standard idiom to make objects of the class non-assignable.