7

I've run into an issue I don't understand and I was hoping someone here might provide some insight. The simplified code is as follows (original code was a custom queue/queue-iterator implementation):

class B
{
public:
    B() {};
    class C
    {
    public:
        int get();
        C(B&b) : b(b){};
    private:
        B& b;
    };
public:
    C get_c() { return C(*this); }
};

int main()
{
    B b;
    B::C c = b.get_c();


    c = b.get_c();
    return EXIT_SUCCESS;
}

This, when compiled, gives me the following error:

foo.cpp: In member function 'B::C& B::C::operator=(const B::C&)':
foo.cpp:46: error: non-static reference member 'B& B::C::b', can't use default assignment operator
foo.cpp: In function 'int main()':
foo.cpp:63: note: synthesized method 'B::C& B::C::operator=(const B::C&)' first required here

I can go around this by using two separate C variables, as they are supposed to be independent 'C' objects, but this only hides the problem (I still don't understand why I can't do this).

I think the reason is that the reference cannot be copied, but I don't understand why. Do I need to provide my own assignment operator and copy constructor?

laura
  • 7,280
  • 4
  • 35
  • 43

4 Answers4

13

This problem has nothing to do with inner classes. In C++ you just can't (re)assign references - they need to be initialised when defined.

A simpler example is:

class B
{
public:
    B(int& i) : ir(i) {};

    int& ir;
};


int main()
{
    int i;
    B b(i);      // Constructor - OK

    int j;
    B bb = B(j); // Copy constructor - OK

    bb = b;      // Assignment - Error
    return 0;
}
mkm
  • 673
  • 5
  • 21
Seb Rose
  • 3,628
  • 18
  • 29
  • Bah, of course you're correct, I can't believe I missed the obvious explanation. Should have had more coffee in the morning :D – laura Dec 02 '09 at 13:13
  • 2
    +1. I find that habitually using "bind" rather than "assign" when talking about references helps me from making this mistake. – Kaz Dragon Dec 02 '09 at 17:03
  • now, I am going to reassign a reference and of course it will compile: int a = 3; int b = 4; int& ref = a; ref = b;. So it is possible to reassign a reference. – friko Sep 17 '13 at 13:25
6

A reference cannot be changed after being given its initial value. This means that it is impossible to write an assignment operator that changes the value of a reference member. If you need to do this, use a pointer instead of a reference.

interjay
  • 107,303
  • 21
  • 270
  • 254
3

Actually, there's a solution to this. You can implement operator= in terms of copy construction, and it will work :) It's a very capable technique for such cases. Assuming you do want to support assignment.

rmn
  • 2,386
  • 1
  • 14
  • 21
  • 1
    Calling a destructor in an assignment operator is a very bad progamming habit. – Sjoerd Aug 06 '10 at 10:00
  • 1
    Firstly thanks for your answer, I had reached this solution on my own but omitted the self-assignment check and explicit destructor call. You note that you don't recommend using it (and I agree with your reasoning), given these disadvantages is there a preferred implementation? – davetapley Nov 02 '10 at 14:39
  • Your link is broken, now you answer is invalid. – Evandro Coan Mar 31 '18 at 18:00
0

C++ doesn't have "inner classes", just nested class declarations. "inner classes" are a Java-ism that I don't think are found in other mainstream languages. In Java, inner classes are special because they contain an implicit immutable reference to an object of the containing type. To achieve the equivalent to C++'s nested declarations in Java requires use of static inner classes; static inner classes do not contain a reference to an object of the declaring type.

DrPizza
  • 17,882
  • 7
  • 41
  • 53