0

I have two classes defined in different h files and each class has some private functions. However, there's one function in each class that I want to be able to access from a function in the other class.

For example...

//apple.h:

class Beets;

class Apple
{
public:
    double  ShadeUsed();
private:
    void    Fruit();
    bool    RedRoots();
    friend  bool Beets::BlueRoots(); //<--- Error b/c not declared yet
};


//beets.h
#include "apple.h"

class Beets
{
    public:
    double  SunNeeded();
private:
    void    Leaves();
    bool    BlueRoots();
    friend  bool Apple::RedRoots();
};

The goal is that only one function in each class should have access to the other classes private stuff. For example, only the root function should have access to the other class's private stuff. However, without the includes becoming circular I cannot achieve reciprocal friendship.

I've considered making for example, the whole Beets class a friend to Apples that way the class pre-declaration would be enough, but I'd rather only allow one function private access.

Any suggestions? Thanks in advance, Matt.

(P.S. why does carriage return between each of "Thanks in advance,", "Matt" not result in newlines?)

Matt
  • 1,327
  • 1
  • 12
  • 21
  • In answer to your P.S., you need two carriage returns to generate a newline. Oh, and I'm having flashbacks to [this question](http://stackoverflow.com/questions/6158760/recursive-friend-classes) (the short answer being that you can't do this). – Chris Frederick May 31 '11 at 18:18
  • @ Chris, I guess then I'll just have to declare the whole class as friend. @ the P.S. If I do two carriage returns there's a whole line between them. I only wanted them to be on separate lines. – Matt May 31 '11 at 18:28
  • Circular dependencies are usually a symptom of a problem in the design, I would try to refactor it to break the dependencies. – David Rodríguez - dribeas May 31 '11 at 18:32

2 Answers2

1

You could use friend functions which call the member functions.

//apple.h:

class Beets;

class Apple
{
public:
    double  ShadeUsed();
private:
    void    Fruit();
    bool    RedRoots();
    friend  bool Beets_BlueRoots(Beets* beets); 
    friend  bool Apple_RedRoots(Apple* apple);
};

bool Apple_RedRoots(Apple* apple);


//beets.h

class Beets
{
    public:
    double  SunNeeded();
private:
    void    Leaves();
    bool    BlueRoots();
    friend  bool Apple_RedRoots();
    friend  bool Beets_BlueRoots(Beets* beets);
};

bool Beets_BlueRoots(Beets* beets);
MRAB
  • 20,356
  • 6
  • 40
  • 33
  • This is the correct solution to this problem. However, as per littleadv's comment, I'm going to change the classes so that I won't need to use friends. – Matt May 31 '11 at 19:19
-2

It appears that you've got some design issue. I would suggest inheritance:

class A{
public:
   virtual bool Roots();
}
class Apples : public A
{}
class Beets : public A
{}

Now, both Apples and Beets have Roots function, without circular includes, and it's public so they can access each other (and the only one public, so you're safe). You don't even need to know if the roots are red or blue. And if you create a "Carrot" class later on, your classes wouldn't need to change to include the "OrangeRoots" as well.

littleadv
  • 20,100
  • 2
  • 36
  • 50
  • Thanks, But I was trying to be clever so I made both classes related to each other. In reality, the two classes are unrelated to each other so inheritance wouldn't work. One class is a I/O class while the other class holds config info on the I/O class... – Matt May 31 '11 at 18:26
  • @Matt, The problem, still, is in your design. If the classes need to access each others private data - they **are** related to each other. What you want to do - cannot be done directly, I suggested you a way to do that indirectly, but it is still an awkward design. If you don't want to do it - try to rethink the whole design to make it correct. In a correct design you wouldn't need friend functions to access private data members of other classes. You're doing something wrong here. – littleadv May 31 '11 at 18:31
  • It is almost *never* appropriate for a config class to know about what it's configuring. It's a code smell 9 times out of 10. – Jonathan Grynspan May 31 '11 at 18:44
  • You're right that there's a design issue. The I/O class was made by someone else and I was extending it with a config class. Because I didn't want to edit too much of the original code I decided to add some of my I/O stuff to the config class. But I guess that was wrong. I'll just have to bite the bullet and merge the I/O parts of the class that I dumped into the config class with the I/O class. Thanks – Matt May 31 '11 at 19:13