Search code examples
c++referencefriendc++03

Initializing a friend's reference member to a class private member


I want to initialize a member (of reference type) in one object to point to a private member of another object (of a different type). I use friend to provide access to the private member. (Please bear with me for a bit, I explain further down why I need to do this.)

Below is a bare minimum version of the code I tried to get started with, and it obviously does not work. Now clearly, I am only trying to initialize the reference with this code Aries a(t.Leo);, but because this is done inside main(), it does not compile.

I went through a number of posts here and on the internet (on the topics of friend and reference), but could not figure out a way to solve it. How could I make this work, or what other approach could I try to bind the reference correctly?

class Aries;

class Taurus {
friend class Aries;
public:
  void setLeo(int inLeo) {
    Leo = inLeo;
  }

private:
  int Leo;
};

class Aries {
public:
  Aries(const int& inCancer) : Cancer(inCancer) {}

private:
  const int& Cancer;
};

int main() {
  Taurus t;
  Aries a(t.Leo);  // Intention: initialize (bind) the Cancer member with t's Leo.
}

Note I know enough C++ to understand why the above practice is considered questionable or bad.

I am working on a research project in a hardware simulation environment, where the testbench is written in C++. The aim of the project is to display the class (private) members as a waveform. The only reliable way of doing this is to make the "waveform maker" class as a friend of the testbench objects, and then have it "stalk" the private members (by creating a reference as above). The other alternative of providing getter methods in the testbench is impractical, since this project would be used with 20 years worth of legacy code.


Solution

  • I know you know that friend is questionable but sometimes necessary, but in this case, these classes don't have to be friends.

    struct AriesBinder {
      AriesBinder(const int& c) : Cancer(c) {}
      const int& Cancer;
    };
    
    class Taurus {
    public:
      void setLeo(int inLeo) {
        Leo = inLeo;
      }
    
      AriesBinder bind() const { return AriesBinder(Leo); }
    
    private:
      int Leo;
    };
    
    class Aries {
    public:
      Aries(const int& inCancer) : Cancer(inCancer) {}
      Aries(AriesBinder b) : Cancer(b.Cancer) {}
    
    private:
      const int& Cancer;
    };
    
    int main() {
      Taurus t;
      Aries b(t.bind());  // Intention was made clear
    }
    

    This is especially useful if many objects like Taurus can be bound to Aries. Also, it decouples the both classes since now the don't have to know each other so you may change the internal representation of Taurus.