2

I am trying to pass a const reference object of class B to an object of class A. So that class A member function foo() can access member function bar() of class B. This below method works fine.

#include <iostream>
using namespace std;

class B {
public:
    void bar() const { cout << "Bar"; }
};

class A {
public:
    A (const B& _b) : b(_b) {}
    void foo () { cout << "Foo"; b.bar(); }
private:
    const B& b;
};

main()
{
     B b1;
     A a1(b1);
     a1.foo();
}

However, instead of passing the b1 object in constructor of A, i am looking for a way to register the object b1 at a later stage. The way mentioned below has errors, but is there any way to achieve this ?

class A {
public:
    A () {};
    void registerB(const B& _b) { b =_b; }      // Assignement not possible
    void foo () { cout << "Foo ";  b.bar(); }
private:
    const B& b;
};

main()
{
     B b1;
     A a1;
     // Do some work
     a1.registerB(b1);
     a1.foo();
}  

EDIT

If the B object is not const, can it be made to work then ?

class A {
public:
    A ():b(NULL) {};
    void registerB(B& _b) { b =_b; }      // Assignement not possible
    void foo () { cout << "Foo ";  b.bar(); }
private:
    B& b;     // Not const
};
kernelman
  • 992
  • 1
  • 13
  • 28
  • 2
    Possible duplicate of [Why can const members be modified in a constructor?](https://stackoverflow.com/questions/49525941/why-can-const-members-be-modified-in-a-constructor) – Joseph D. Apr 24 '18 at 04:58
  • 2
    `void registerB(B& _b) { b =_b; }` *copies* `_b`. `A (const B& _b) : b(_b) {}` *references* `_b`. By design you can't change what object a reference points to – Caleth Apr 24 '18 at 10:38

2 Answers2

1

A reference must refer to a variable. Unlike a pointer, it can not have a value indicating emptiness (like nullptr).

As such, class A cannot have a reference that is not assigned in the constructor. What would a1.b be equal to before you called a1.registerB(b1)?

The only way to do this, would be for class A to have a pointer to a class B. That way it could be null when A is constructed.

i.e.

class A {
    public:
       A():pb(nullptr) {};
       void registerB(const B *_pB) { pB = _pB; }
    private:
       const B *pB;   
}
Murphy
  • 3,827
  • 4
  • 21
  • 35
bpeikes
  • 3,495
  • 9
  • 42
  • 80
  • Thanks for the quick response, i understand. But can it be done with reference but without const ? – kernelman Apr 24 '18 at 04:27
  • 1
    I'm not sure what you mean? Where do you not want the const? You can't have A store a reference to B without initializing it in the constructor, you can only store a pointer. You can have your function registerB take a ref though and then capture the address of it, but it's not a great idea since the caller doesn't know that it's passing it's address to someone else. ie void registerB(B &b) { pB = &b; } – bpeikes Apr 24 '18 at 04:35
  • Thanks a lot. Exactly this is what i wanted. Storing the reference in a pointer made sense, the registerB function can sill be have reference type as argument. – kernelman Apr 24 '18 at 04:44
  • 1
    kernelman - I would stay away taking a reference and then storing a pointer unless you absolutely have to. It's much clearer to have void registerB(B *_pB) { pB = _pB; } and then call it like a.registerB(&b); Then at least caller knows that their address might be captured. At the end of the day, who owns the "B"? By capturing the address, you have to be careful that B does not go out of scope. – bpeikes Apr 24 '18 at 04:54
1

Another way is to create a temporary object for a reference.

class A {
public:
    A() : b{} {} // create temporary
    void registerB(B& _b) { b = _b; }  // Assign later
    void foo () { std::cout << "Foo ";  b.bar(); }
private:
    B&& b;
};

NOTE: this will have a warning:

a temporary bound to 'A::b' only persists until the constructor exits [-Wextra]

Thus, this will cause undefined behavior if you forgot to call registerB().

See more Prolong life of a temporary object using const reference

Joseph D.
  • 11,804
  • 3
  • 34
  • 67