Вопрос по c++, friend – Укажите функцию-член класса как друга другого класса?

14

В соответствии с книгой C ++ Primer, автор упомянул, что мы можем указать функцию-член класса как друга другого класса, а не весь класс (стр. 634).

Затем я проверил этот код:

<code>class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};
</code>

Я просто хотел, чтобы fB () был другом класса A, а не всего класса B. Но код about выдал ошибку:'B' : is not a class or namespace name. (I am using Visual C++ 2005)

Ваш Ответ

7   ответов
0

вперед объявить класс A, так что его видно в определении класса B. затем определите класс A, содержащий функцию друга из класса B.

16

class A; // forward declaration of A needed by B

class B
{
public:
    // if these require full definition of A, then put body in implementation file
    void fB(A& a); // Note: no body, unlike original.
    void fB2(A& a); // no body.
};

class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};

A необходимо полное определениеB, Тем не мение,B нужно знать оA, но не нуждается в полном определении, поэтому вам нужно предварительное объявлениеA.

@ipkiss да, потому что тогда вам понадобится полное определение в объявлении класса заголовка. Но если вы сделали это в отдельном файле реализации, вы могли бы включить полное объявление A.
Но если в fB (A & amp; a) я использую a для доступа к переменной в A, например, a.variable; это было бы незаконно, потому что А еще не было определено. ipkiss
0

@juanchopanza @ipkiss Что касается проблемы, заключающейся в том, что вы не можете получить доступ к элементам данных A внутри fB (A & amp; a), поскольку A еще не определено. чтобы определять его в отдельном файле и включать в него, вы можете просто определить функцию fB (A & amp; a) после определения класса A, чтобы fB (A & amp; a) могла видеть элементы данных A.

3

B должно быть известно до определенияA.

Так что вперед объявляюA, посколькуB не нуждается в полном типе и переключается между определениями:

class A;
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};
class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};
2

троку:

friend void B::fB(A& a);

Тогда компилятор не понимает, что вы подразумеваете под этимB::, Даже если вы определили этот класс позже в коде, но компилятор этого не знает. Так что обычно полезно практиковать предварительное объявление класса (class Name; ) если определение находится позже в коде.

0

прежде чем использовать конкретное имя класса, вам нужно сначала объявить его. Таким образом, вам потребуется предварительное объявление класса B, поскольку вы используете его в классе A, до того, как класс B был первоначально объявлен.

Во-вторых, вам нужно будет определить функции (которые используют переменные из обоих классов, в данном случае это дружественные функции) после того, как оба класса были определены. Или мы можем столкнуться с ошибками.

Например

#include<iostream>

using namespace std;

class alpha1;

class alpha2
{
    public:

        void put_bata(int a,int b);
};

void alpha2 :: put_bata(int a,int b)
{
    alpha1 net;

    net.roll=a;

    net.id=b;

    net.get_data();
}

class alpha1
{
    int roll;

    int id;

    public:

        void get_data(void)
        {
            cout<<roll<<endl<<id<<endl;
        }

        friend void alpha2 :: put_bata(int a,int b);
};

int main()
{
    alpha2 gamma;

    gamma.put_bata(5,6);

    return 0;
}

Мы покажем нам ошибки, так как put_bata пытается получить доступ к roll и id до того, как они будут определены, даже если у нас было предварительное объявление класса th, e, но приведенный ниже код будет работать нормально.

#include<iostream>

using namespace std;

class alpha1;

class alpha2
{
    public:

        void put_bata(int a,int b);
};

class alpha1
{
    int roll;

    int id;

    public:

        void get_data(void)
        {
            cout<<roll<<endl<<id<<endl;
        }

        friend void alpha2 :: put_bata(int a,int b);
};

void alpha2 :: put_bata(int a,int b)
{
    alpha1 net;

    net.roll=a;

    net.id=b;

    net.get_data();
}


int main()
{
    alpha2 gamma;

    gamma.put_bata(5,6);

    return 0;
}
3

т эту строку:

friend void B::fB(A& a);
at this point, compiler has no idea about type info of B so it throws an error ( 'B' : is not a class or namespace name ).

by forward declaration of class B, compiler knows about type of B is Class in advance to its actual declaration with all members.

run below code after forward declaration of class B.

///////////////

class B;
class A
{
public:
    friend void B::fB(A& a); 
    void fA(){};
};
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};

Все еще ошибка !!!

потому что предварительное объявление - это просто объявление идентификатора, для которого программист еще не дал полного определения. поэтому компилятору нужно полное определение B перед классом A.

Примечание: определение класса A зависит от типа B, а также от определения B (т.е. B :: fB), поэтому одно только предварительное объявление не может разрешиться, полное определение класса B необходимо определить перед классом A.

4 запустить этот код

////////

class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};
class A
{
public:
    friend void B::fB(A& a); 
    void fA(){}
};

Все еще ошибка !!!

потому что функции-члены класса B fB & amp; fB2 имеет аргументы типа A, но компилятор не имеет представления об информации о типе A, поэтому путем прямого объявления класса A мы можем сообщить компилятору об информации о типе A.   Примечание: определение класса B зависит только от типа A, а не от членов A, поэтому предварительное объявление A решает шаг 4.

final code

////////////////////////

class A;  // forward declaration of A needed by B
class B
{
public:
    void fB(A& a);
};

class A
{
    int i;
public:
    friend void fA(A& a);    //specifying function fA as a friend of A, fA is not member function of A
    friend void B::fB(A& a); //specifying B class member function fB as a friend of A
};

// fA is Friend function of A
void fA(A& a)
{
    a.i  = 11; // accessing and modifying Class A private member i
    cout<<a.i<<endl;
}

// B::fB should be defined after class A definition only because this member function can access Class A members
void B::fB(A& a)
{
    a.i  = 22; // accessing and modifying Class A private member i in Class B member function fB
    cout<<a.i<<endl;
}

int main()
{
    A a;
    fA(a);    // calling friend function of class A

    B b;
    b.fB(a);  // calling B class member function fB, B:fB is friend of class A

    return 0;
}

6 Упражнение:

// Cyclic dependency 
#include<iostream>
using namespace std;

class A;

class B
{
public:
    void fB(A& a);
    friend void A::fA(B& b); //specifying class A's member function fA as a friend of B
};

class A
{
    int i;
public:
    void fA(B& b);  
    friend void B::fB(A& a); //specifying class B's member function fB as a friend of A
};

int main()
{
    return 0;
}
Итак, как вы решаете упражнение?
@ BrunoMartinez - идеального решения для этого не существует, потому что оба циклически зависят от полного определения друг друга. Мое намерение представить этот особый случай состояло в том, чтобы подчеркнуть важность разделения сущностей в разработке программного обеспечения и получить больше ясности в отношении функции Friend, работая над этим. Я думаю, вы, возможно, уже знаете, что возможным вариантом для этого является создание общей функции друга

Похожие вопросы