0

I'm having some difficulties with friend functions in C++, but my suspicion is that is more of a symptom of a problem I have with preprocessor directives and #include.

This is a silly example of what I was doing. Five files: bobby.h, bobby.cpp, billy.h, billy.cpp, and main.cpp. Billy has a protected function called ReceiveMoney. Bobby has a function called bank that calls Billy's ReceiveMoney. i.e. every time Bobby goes to the bank he splits the money with Billy.

billy.h

#ifndef BILLY_H
#define BILLY_H
#include "bobby.h"

class Billy
{
friend void Bobby::Bank(int, Billy &);
public:
    Billy();
protected:
    void ReceiveMoney(int inc);
private:
    int money;
};
#endif

billy.cpp

#include "billy.h"

Billy::Billy()
{
    money = 0;
}

void Billy::ReceiveMoney(int inc)
{
    money+=inc;
}

bobby.h

#ifndef BOBBY_H
#define BOBBY_H

#include "billy.h"

class Bobby
{
public:
    Bobby();
    void Bank(int amount, Billy & b);
protected:
    int money;
};
#endif

bobby.cpp

#include "bobby.h"

Bobby::Bobby()
{
    money = 0;
}
void Bobby::Bank(int amount, Billy & b)
{
    b.ReceiveMoney(amount/2);
}

main.cpp

#include "billy.h"
#include "bobby.h"

int main()
{
    Bobby bo;
    Billy bi;
    bo.Bank(150, bi);
    return 0;
}

I get a large number of errors, usually error C2653: 'Bobby' : is not a class or namespace name or error C2653: 'Billy' : is not a class or namespace name

I'm doing this in an empty console project in VS0

Tim
  • 301
  • 1
  • 5
  • 8

3 Answers3

3

You have a Circular dependency of header files.
billy.h includes bobby.h, while bobby.h includes billy.h.
Obviously, the compiler cannot make out the types due to this circular dependency.

The best solution is to rethink your design and avoid the circular dependency or
Use Forward declarations to break the circular dependency.

Just forward declare class Billy in bobby.h

//#include "billy.h"     <-----  You don't need this include 
class Billy;             <-----  Just Forward Declaration should suffice

You can use a forward declaration here because, Declare functions or methods which accepts/return incomplete types, in this case Billy is an Incomplete type for the compiler.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Well, I'm not completely new at this. I did try forward declarations. The line b.ReceiveMoney(amount/2); in bobby.cpp causes an error for use of undefined type 'Billy' – Tim May 15 '12 at 10:29
  • @Tim: Include `billy.h` in `bobby.cpp`. – Alok Save May 15 '12 at 10:37
1

There is a loop in your #include, you cannot do that. You must use a forward declaration of Bobby in billy.h. Such as class Bobby;. You won't be able to declare the friend function even with that.

The only real solution is to avoid the need for a friend. ReceiveMoney should be public in fact: if Bobby represents something like an account, it is logical.

The constraints on friend makes it useful only to solve inner behaviour of classes (for example with collections and nodes implementing them).

armel
  • 2,497
  • 1
  • 24
  • 30
  • What I wanted was to have a function that was only usable by a certain class and only in a certain function of that class. I can't imagine that there is not a way to do that. – Tim May 15 '12 at 10:36
  • I understand what you attempt to do, but in OO you typically do that the other way: you make public what needs to be called from other classes of your own, and you make an interface from which Billy would derive, which you actually provide to the "customers" of your code. The interface would not contain ReceiveMoney in your case. – armel May 15 '12 at 10:41
0

Due to circular dependency none of the classes are fully defined. hence the large number of errors. If possible change your design and inherit or include only things necessary. As mentioned by Als forward declarations can be a choice. Circular dependencies mostly arise due to design faults.

Rohit Vipin Mathews
  • 11,629
  • 15
  • 57
  • 112