tags:

views:

152

answers:

4

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?

+2  A: 

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.

Tyler McHenry
I think this is the way to go, but I'll just change both equal operators for consistency.
Jonas
A: 

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.

Charlie Martin
-1 because reading his code shows that he already tried to do this. The problem is that both classes reference each other, causing a circular dependency.
e.James
A: 

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.

shoosh
If they're not friends then I can't copy them so easy. The solution would then be that I can't copy them at all. I could use a member function or a copy factory or something silly but then that would have to be a friend too...
Jonas
A: 

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; }
};
e.James
@recent downvoter: What was my error?
e.James