Задать функцию-член класса как друг другого класса?

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

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

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

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

7 ответов


попробуйте поставить определение B перед A:

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.


для этого, чтобы работать, полное определение 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(){}
};

когда компилятор начинает читать код( обычно сверху ) и он встречает эту строку:

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

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


когда компилятор начинает компиляцию кода (обычно сверху ), и он сталкивается с этой строкой:

friend void B::fB(A& a);
  1. на данный момент компилятор понятия не имеет о типе информации B, поэтому он выдает ошибку ( 'B' : не является именем класса или пространства имен ).
  2. при прямом объявлении класса B компилятор знает о типе B является классом заранее до его фактического объявления со всеми членами.

  3. выполнить ниже кода после прямого объявления класса Б.

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

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

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

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

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

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 & fB2, имеющие аргументы типа A, но компилятор не имеет представления о типе информации so путем прямого объявления класса A, мы можем позволить компилятору знать о типе информации A. Примечание: определение класса B зависит только от типа A, а не от членов A, так что прямое объявление шага разрешения 4.

  1. код

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

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;
}

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


прежде всего, прежде чем использовать конкретное имя класса, вам нужно будет сначала объявить его. Таким образом, вам понадобится прямое объявление класса 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, прежде чем они будут определены, даже если у нас было прямое объявление класса, но код, приведенный ниже, будет работать нормально.

#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;
}

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