20

根据 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()成为朋友class A,而不是整个class B。但是上面的代码产生了一个错误:'B' : is not a class or namespace name. (我正在使用 Visual C++ 2005)

4

7 回答 7

22

尝试将 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

于 2012-05-11T06:24:02.073 回答
6

当编译器开始编译代码(通常从顶部)并遇到这一行:

friend void B::fB(A& a);
  1. 此时,编译器不知道 B 的类型信息,因此会引发错误( 'B' : is not a class or namespace name )。

  2. 通过类 B 的前向声明,编译器在其与所有成员的实际声明之前就知道 B 的类型是 Class。

  3. 在 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){};
};

还是错误!!!

因为前向声明只是程序员尚未给出完整定义的标识符的声明。因此编译器需要在 A 类之前对 B 进行完整定义。

注意: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 和 fB2 具有 A 类型的参数,但编译器不知道 A 的类型信息,所以通过 A 类的前向声明,我们可以让编译器知道 A 的类型信息。注意:B 类定义仅依赖于A 的类型不是 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;
}
于 2015-03-19T05:07:35.677 回答
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(){}
};
于 2012-05-11T06:23:14.073 回答
2

当编译器开始读取代码(通常从顶部)并遇到此行时:

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

然后编译器不明白 this 是什么意思B::。即使您稍后在代码中定义了此类,但编译器也不知道。因此,class Name;如果定义位于代码的后面,那么练习前向声明 class() 通常是一个好习惯。

于 2015-02-24T18:45:59.107 回答
0

@juanchopanza @ipkiss 关于由于 A 尚未定义而无法在 fB(A& a) 中访问 A 的数据成员的问题。您可以在定义类 A 之后定义函数 fB(A& a),以便 fB(A& a) 能够看到 A 的数据成员,而不是将其定义在单独的文件中并包含它。

于 2014-12-23T12:25:38.240 回答
0

首先向前声明A类,使其在B类定义中可见。然后定义包含类 B 的友元函数的类 A。

于 2014-11-26T12:38:57.997 回答
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,即使我们有该类的前向声明,但下面给出的代码也可以正常工作。

#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;
}
于 2014-12-20T13:38:06.883 回答