It's time for my first question now. How do you cross assignments operators between two classes?
class B;
class A {
public:
A &operator = ( const B &b );
friend B &B::operator = ( const A &a ); //compiler error
};
class B {
public:
B &operator = ( const A &a );
friend A &A::operator = ( const B &b );
};
I searched for how to forward declare a member function like:
class B;
B &B::operator = ( const A &a ); //error
But I didn't find anything. And I don't want to make the classes all-out friends with each other. How do I do this?
There is no way to forward-declare member functions. I'm not sure if there is a more elegant way than this to get what you want (I've never had reason to do something like this), but what would work would be to make for the second class a non-member function that is a friend to both classes, and delegate copying to it. Note that operator= cannot be itself a non-member, but something like this should work:
class B;
class A {
public:
A& operator = ( const B &b );
friend B& do_operator_equals ( B& b, const A& b);
};
class B {
public:
B &operator = ( const A &a );
friend A& A::operator = ( const B &b );
friend B& do_operator_equals ( B& b, const A& a);
};
And then in your implementation file
A& A::operator= (const B& b) {
// the actual code to copy a B into an A
return *this;
}
B& B::operator= (const A& a) {
return do_operator_equals(*this, a);
}
B& do_operator_equals(B& b, const A& a) {
// the actual code to copy an A into a B
return b;
}
Edit: Got the A's and B's backwards, oops. Fixed.
The reason for the compiler error is a circular dependency. Each of your operator=() functions require knowledge of the operator=() function inside the other class, so no matter which order you define your classes in, there will always be an error.
Here is one way to sort it out. It isn't very elegant, but it will do what you want:
class A;
class B;
A & set_equal(A & a, const B & b);
B & set_equal(B & a, const A & a);
class A
{
private:
int x;
public:
A & operator=(const B & b) { return set_equal(*this, b); }
friend B & set_equal(B & b, const A & a);
friend A & set_equal(A & a, const B & b);
};
class B
{
private:
int y;
public:
B & operator=(const A & a) { return set_equal(*this, a); }
friend A & set_equal(A & a, const B & b);
friend B & set_equal(B & b, const A & a);
};
A & set_equal(A & a, const B & b) { a.x = b.y; return a; }
B & set_equal(B & b, const A & a) { b.y = a.x; return b; }
You may also be able to solve this problem with inheritance.
edit: here is an example using inheritance. This will work if the copying procedure only needs access to some common data shared by both A and B, which would seem likely if the = operator is to have any meaning at all.
class A;
class B;
class common
{
protected:
int x;
void copyFrom(const common & c) { x = c.x; }
};
class A : public common
{
public:
A & operator=(const common & c) { copyFrom(c); return *this; }
};
class B : public common
{
public:
B & operator=(const common & c) { copyFrom(c); return *this; }
};
Why do you want them to be friends in the first place?
This seem to be impossible the way you write it. The solution would probably be to not have them as friends at all.
You don't forward declare the member function, you forward declare the class.
class B; // DECLARE class B but don't define its contents
class A { // ... uses B as above
};
class B { // ... now you define the class.
};
See the C++ FAQ section 39.
Related
This is a grossly simplified version of what I am doing but gets the point across. I have 2 classes that can be used for arithmetic. My problem is I want to be able to multiply the 2 together but anyway I try this seems to cause a problem. For example:
class A {
uint32_t val_;
A(uint32_t src) {
val_=src;
}
friend A operator* (const A &a,const B &b); // <------ throws Unknown type B
};
class B {
uint32_t val_;
bool invert_;
B(A src,bool invert) {
val_=src.val_;
invert_=invert;
}
friend A operator* (const A &a,const B &b);
};
A operator* (const A &a,const B &b) {
if (b.invert_) return a.val_/b.val_;
return a.val_*b.val_;
}
how can I get around this seeming recursive error? If it wasn't for the B value always comes second I would put A operator* (const A &a); in the B class so I can just use friend class B in the A class
So the problem is I didn't know the term forward declaration.
class B; //forward declare B
class A {
uint32_t val_;
A(uint32_t src) {
val_=src;
}
friend A operator* (const A &a,const B &b);
};
class B {
uint32_t val_;
bool invert_;
B(A src,bool invert) {
val_=src.val_;
invert_=invert;
}
friend A operator* (const A &a,const B &b);
};
A operator* (const A &a,const B &b) {
if (b.invert_) return a.val_/b.val_;
return a.val_*b.val_;
}
simple fix when you know the term.
Here is a very simple class hierarchy:
class A
{
public:
A( int _a ) : a( _a ) {}
virtual bool operator==( const A& right ) const
{
return a == right.a;
}
virtual bool operator!=( const A& right ) const
{
return !( *this == right );
}
int a;
};
class B : public A
{
public:
B( int _a, int _b ) : A( _a ), b( _b ) {}
virtual bool operator==( const B& right ) const
{
return A::operator==( right ) && b == right.b;
}
int b;
};
As you can see, operator != is defined in the base class. Because I'm very lazy, I don't want to duplicate such a simple code in all the derived classes.
Unfortunatley, with this code:
A a4(4), a5(5), a4bis(4);
assert( a4 == a4bis );
assert( a4 != a5 );
B b1(4,5), b2(4,6);
assert( !(b1 == b2) );
assert( b1 != b2 ); // fails because B::operator== is not called!
b1 != b2 returns false, because it executes A::operator!= which calls then A::operator== rather than B::operator== (even if the operator is virtual, as derived class version parameter is different, they are not linked in the vtable).
So what's the best way to adress != operator in a generic way for a class hierarchy?
One solution is to repeat it in each class, B would then have:
virtual bool operator!=( const B& right ) const
{
return !( *this == right );
}
But that's a pain when you have many classes....I have 30....
Another solution would be to have a generic template approach:
template <class T>
bool operator!=( const T& left, const T& right )
{
return !( left == right );
}
But this bypasses any != operator defined by any class....so it may be risky if one declared it differently (or if one declared a == itself calling !=, it would end up with an infinite loop...). So I feel this solution being very unsafe....except if we can limit the template to be used for all classes derived from the top-level class of our hierarchy (A in my example)....but I don't think this is doable at all.
Note: I'm not using C++11 yet...sorry about that.
Your function in B...
virtual bool operator==( const B& right ) const
...does not override the function in A...
virtual bool operator==( const A& right ) const
...because the argument types differ. (Differences are only allowed for covariant return types.)
If you correct this, you'll then be able to choose how to compare B objects to other A and A-derived objects, e.g. perhaps:
bool operator==( const A& right ) const override
{
if (A::operator==( right ))
if (typeid(*this) == typeid(right))
return b == static_cast<const B&>(right).b;
return false;
}
Note that using the typeid comparison above means only B objects will compare equal: any B will compare unequal to any B-derived object. This may or may not be what you want.
With an implementation for B::operator==, the existing != implementation will properly wrap operator==. As Jarod42 observes, your A::operator== isn't robust in that when the left-hand-side value is an A only the A slice of the right-hand-side object will be compared... you might prefer:
virtual bool operator==(const A& right) const
{
return a == right.a && typeid(*this) == typeid(right);
}
This has the same issues as the B::operator== above: e.g. an A would compare un-equal to a derived object that didn't introduce further data members.
How about something like this ?
class A {
protected :
virtual bool equals(const A& right) const {
return (a == right.a);
}
public :
A(int _a) : a(_a) { }
bool operator==(const A& right) const {
return this->equals(right);
}
bool operator!=(const A& right) const {
return !(this->equals(right));
}
int a;
};
class B : public A {
protected :
virtual bool equals(const A& right) const {
if (const B* bp = dynamic_cast<const B*>(&right)) {
return A::equals(right) && (b == bp->b);
}
return false;
}
public :
B(int _a, int _b) : A(_a), b(_b) { }
int b;
};
Move the comparison logic to a separate (virtual) function equals, and call that function from the operator== and operator!= defined in the base class.
The operators don't need to be re-defined in the derived classes. To change the comparison in a derived class, simply override equals.
Note that the dynamic_cast in the code above is used to ensure that the runtime type is a valid type for performing the comparison. Ie. for B::equals, it's used to ensure that right is a B - this is necessary because otherwise right would not have a b member.
I have seen many example to add objects of same class.I was trying to add two different class objects using operator overloading.
Code:
#include<iostream>
using namespace std;
class B;
class A
{
public:
int x;
A(int t=99)
{
x=t;
}
friend const A operator+( A& m, B& n);
friend ostream& operator<<(ostream& os, const A& c);
};
const A operator+(A& c1,B& c2)
{
A temp;
temp.x = c1.x + c2.y;
return temp;
}
ostream& operator<<(ostream &os, const A& c)
{
os << c.x;
return os;
}
class B
{
public:
int y;
B(int e=90)
{
y=e;
}
friend const A operator+( A& m, B& n);
};
int main()
{
A a,u;
B b;
u=a+b;
cout<<"Value of A+B"<<u;
return 0;
}
When i compiled my code it shows Error:
$ g++ operator_overloading.cpp
operator_overloading.cpp: In function ‘const A operator+(A&, B&)’:
operator_overloading.cpp:19:21: error: invalid use of incomplete type ‘struct B’
operator_overloading.cpp:3:7: error: forward declaration of ‘struct B’
What i have done wrong??
The error is clear. You have attempted to use members of B using only a forward declaration.
You have to define the operator after the definition of class B.
For example
#include<iostream>
using namespace std;
class B;
class A
{
public:
int x;
A(int t=99)
{
x=t;
}
friend const A operator+( const A& m, const B& n);
friend ostream& operator<<(ostream& os, const A& c);
};
ostream& operator<<(ostream &os, const A& c)
{
os << c.x;
return os;
}
class B
{
public:
int y;
B(int e=90)
{
y=e;
}
friend const A operator+( const A& m, const B& n);
};
const A operator+(const A& c1, const B& c2)
{
A temp;
temp.x = c1.x + c2.y;
return temp;
}
//...
Otherwise the compiler does not know what data members class B has.
Also it is better to define paraneters of the operator as constant references. In this case the operator can deal with temporary objects.
The error message is caused by the fact that you've defined your const A operator+(A& c1,B& c2) before defining the class B.
At this moment B is hence still an incomplete type (meaning you can only use pointers and references to it, but nothing else).
Just move this definition after you've defined B.
The line class B; forward-declares B. This tells the compiler that a class called "B" exists, but nothing else. When you attempt to use c2.y, where c2 is a B, the compiler does not yet know that B even has a y member.
One solution in this case is to move the definition of B so that it appears before the operator+ definition:
class B;
class A
{
public:
int x;
A(int t=99)
{
x=t;
}
friend const A operator+( A& m, B& n);
friend ostream& operator<<(ostream& os, const A& c);
};
class B
{
public:
int y;
B(int e=90)
{
y=e;
}
friend const A operator+( A& m, B& n);
};
const A operator+(A& c1,B& c2)
{
A temp;
temp.x = c1.x + c2.y;
return temp;
}
I have this class :
class A
{
public:
//copy and move constructor,operator=
A func(const A& a,const A& b)
{
A c;
//do some stuff...
return c;
}
};
It works fine when I use it in this way :
A a;
A b;
A c=func(a,b);
But the problem is when I use it in this way :
A a;
A b;
a=func(a,b);
It does some unnecessary stuff (making c and in my class calling constructor is time consuming!)
I want to know if a is equal to one of variables that pass to function then I don't make c and do stuff in-place
After thinking for a while I came up with this solution :
class A
{
public:
//copy and move constructor and operator=
A func(const A& a,const A& b)
{
A c;
//do some stuff...
return c;
}
A func(const A& a,const A& b,bool inPlace)
{
if(!inPlace)
return func(a,b);
else
{
//const-cast a then do stuff on a
return a;
}
}
};
now It works fine with :
A a;
A b;
A c=func(a,b);
a=func(a,b,true);
But still it doesn't work with :
A a;
A b;
b=func(a,b,true);
So another overload for func is needed .
But It seems a bad design . Any better idea for making this class ?
Note that I don't want to make func like this :
void func(const A& a,const A& b,A& result)
(And sorry about the question title I cant find a better one :) )
EDIT
My constructor looks like this :
A(unsigned int SIZE)
{
// all of these are vectors and SIZE is about 1k
realData_.reserve(SIZE);
timePerUnit_.reserve(SIZE);
prob_.reserve(SIZE);
//....
// some math stuff for filling them
}
From how I understand your question you want to write a A &func(const A& a,const A& b) which returns a newly constructed A. But as an optimization you want to modify a or b and not construct a new A if the result of func is assigned to a or b.
When you are writing a = func(a, b) this is like a.operator=(func(a, b)). func will not know how its return value is used and operator= will not know that its parameter is coming from func. If you want to optimize for that special case you need to write extra functions for it.
You could write an unoptimized and an optimized version:
A &func(const A& a, const A& b) { A c; ...; return c; }
void func(A& a, const A& b) { modify a; }
void func(const A& a, A& b) { modify b;}
// In case func(a,b)==func(b,a) for const a and const b you can write:
void func(const A& a, A& b) { func(b, a); }
Or you could write a generic version:
void func(const A& a, const A& b, A& result)
{
if(&result == &a)
optimized modify result;
else if(&result == &b)
optimized modify result;
else
unoptimized modify result;
}
In case you are lucky you do not even need to distinguish between the different cases in the generic version. But this depends on the calculations you are doing.
BTW, if you are looking at the STL you will see that they are doing something similar. Replace A with string and func with operator+ and you will end up with string operator+ (const string& lhs, const string& rhs);. This operator will always create a new object which it returns. To optimize for the case str1 = str1 + str2; the STL declares an extra function operator+=. That's the same thing that you will need to do - only that your functions have the name func and not operator ... .
If you definitely don't want to use:
void func(const A& a, const A& b, A& result)
Then you can get away with a single overload by using a pointer for your third argument instead of a bool, like:
A func(const A& a, const A& b, const A* resultPlace = NULL)
{
if (resultPlace == &a) {
// Do in place stuff with a
return a;
}
else if (resultPlace == &b) {
// Do in place stuff with b
return b;
}
else {
A c;
// whatever
return c;
}
}
Of course, you would call this like: b = func(a, b, &b);
Not sure if you can do any better than this, but I doubt you'll be able to do what your question title asks specifically.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Operator overloading
What causes C++ compiler error: must have argument of class or enumerated type?
I am trying to play a little bit with operator overloading and genericity in C++ and I seem to have 3 little errors when I try to compile. Have a class named Grandeur with template D, and then I inherit 3 classes from this one, named Temps(time), Longueur(size), Vitesse(speed), and I am trying to overload the operators such as when I do Temps+Temps->Temps, Vitesse+Vitesse=Vitesse,Longueur+Longueur->Longueur, Longueur/Time->Vitess etc.
In order not to write 3 times the same functions for the operations of same type, I use templates to utilise the genericity. But I have an error when I try to compile. Here is my code:
typedef double Longueur;
typedef double Temps;
typedef double Vitesse;
template<typename D>
class Grandeur {
protected :
double val; const char* unite;
public :
Grandeur(double qqc) : val(qqc) {}
Grandeur(int qqc) : val(qqc) {}
Grandeur(long qqc) : val(qqc) {}
Grandeur(float qqc) : val(qqc) {}
inline friend D operator+ (const D a, const D b) {
return D (a.val + b.val);
}
inline friend D operator- (const D a, const D b) {
return D (a.val - b.val);
}
inline friend double operator* (const D a, const D b) {
return a.val * b.val;
}
inline friend double operator/ (const D a, const D b) {
return a.val / b.val;
}
inline friend D operator* (D a, const int b) {
return D (a.val * b);
}
inline friend D operator/ (const D a, const int b) {
return D (a.val / b);
}
inline friend ostream& operator<< (ostream& os, D d) {
return os << d.val << d.u;
}
class Temps : public Grandeur<Temps> {
public:
};
class Vitesse : public Grandeur<Vitesse> {
public:
};
class Longueur : public Grandeur<Longueur> {
public:
};
};
inline Longueur operator* (const Vitesse v, const Temps t) {
return Longueur(v.val * t.val);
}
inline Vitesse operator/ (const Longueur l, const Temps t) {
return Vitesse(l.val / t.val);
}
inline Temps operator/ (const Longueur l, const Vitesse v) {
return Temps(l.val / v.val);
}
When I try to compile it says:
g++ essai.cc
In file included from essai.cc:4:0:
grandeurs.h:70:58: error: ‘Longueur operator*(Vitesse, Temps)’ must have an argument of class or enumerated type
grandeurs.h:74:58: error: ‘Vitesse operator/(Longueur, Temps)’ must have an argument of class or enumerated type
grandeurs.h:78:58: error: ‘Temps operator/(Longueur, Vitesse)’ must have an argument of class or enumerated type
The lines 70, 74 and 78 are those with the last 3 functions (the inlines). What can I do?
You're declaring the operators at global scope so the types Vitesse etc are not available to the compiler. Why not move the child classes outside Grandeur<T>'s definition?
EDIT for comment:
You're trying to use the operators with double values, but the implicit conversions are not automatically inherited by your child classes. You'll need to define them in each child and pass the parameters up to the parent template class.