проблемы с функцией друга

У меня есть некоторые трудности с дружественными функциями в C++, но я подозреваю, что это скорее симптом проблемы, которая у меня есть с директивами препроцессора и #include.

Это глупый пример того, что я делал. Пять файлов: bobby.h, bobby.cpp, billy.h, billy.cpp и main.cpp. У Билли есть защищенная функция ReceiveMoney. У Бобби есть функция, называемая банком, которая вызывает функцию ReceiveMoney Билли. то есть каждый раз, когда Бобби идет в банк, он делит деньги с Билли.

Билли.ч

#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

Билли.cpp

#include "billy.h"

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

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

Бобби.h

#ifndef BOBBY_H
#define BOBBY_H

#include "billy.h"

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

Бобби.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;
}

Я получаю большое количество ошибок, обычно ошибка C2653: «Бобби»: не имя класса или пространства имен или ошибка C2653: «Билли»: не имя класса или пространства имен

Я делаю это в пустом консольном проекте в VS0.


person Tim    schedule 15.05.2012    source источник


Ответы (3)


У вас есть циклическая зависимость файлов заголовков.
billy.h включает bobby.h, а bobby.h включает billy.h.
Очевидно, компилятор не может определить типы из-за этой циклической зависимости.

Лучшее решение — переосмыслить свой дизайн и избежать циклической зависимости или
использовать Forward объявления, чтобы разорвать циклическую зависимость.

Просто вперед объявите класс Billy в bobby.h

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

Вы можете использовать здесь предварительное объявление, потому что объявляйте функции или методы, которые принимают/возвращают неполные типы, в этом случае Billy является неполным типом для компилятора.

person Alok Save    schedule 15.05.2012
comment
Ну, я не совсем новичок в этом. Я пробовал предварительные объявления. Строка b.ReceiveMoney(сумма/2); в bobby.cpp вызывает ошибку использования неопределенного типа «Билли» - person Tim; 15.05.2012
comment
@Tim: включить billy.h в bobby.cpp. - person Alok Save; 15.05.2012
comment
Спасибо, вы очень помогли. - person Tim; 15.05.2012

В вашем #include есть цикл, вы не можете этого сделать. Вы должны использовать предварительное объявление Bobby в billy.h. Например, class Bobby;. Даже с этим вы не сможете объявить функцию друга.

Единственное реальное решение состоит в том, чтобы избежать необходимости в friend. ReceiveMoney на самом деле должно быть общедоступным: если Бобби представляет собой что-то вроде учетной записи, это логично.

Ограничения на friend делают его полезным только для решения внутреннего поведения классов (например, с коллекциями и реализующими их узлами).

person armel    schedule 15.05.2012
comment
Я хотел иметь функцию, которую можно было бы использовать только в определенном классе и только в определенной функции этого класса. Я не могу себе представить, что нет способа сделать это. - person Tim; 15.05.2012
comment
Я понимаю, что вы пытаетесь сделать, но в ООП вы обычно делаете это по-другому: вы делаете общедоступными то, что нужно вызывать из других ваших собственных классов, и вы создаете интерфейс, из которого Билли будет производным, который вы фактически предоставляете для клиенты вашего кода. В вашем случае интерфейс не будет содержать ReceiveMoney. - person armel; 15.05.2012

Из-за круговой зависимости ни один из классов не определен полностью. отсюда и большое количество ошибок. Если возможно, измените свой дизайн и наследуйте или включите только то, что необходимо. Как упоминалось Als, предварительные объявления могут быть выбором. Круговые зависимости в основном возникают из-за ошибок проектирования.

person Rohit Vipin Mathews    schedule 15.05.2012