将类成员函数指定为另一个类的朋友?

时间:2012-05-11 06:21:30

标签: c++ friend

根据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类。但是代码产生了一个错误:'B' : is not a class or namespace name。 (我使用的是Visual C ++ 2005)

7 个答案:

答案 0 :(得分:16)

尝试将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的前向声明。

答案 1 :(得分: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 :(得分:3)

当编译器开始编译代码时(通常是从顶部开始),它会遇到这一行:

friend void B::fB(A& a);
  1. 此时,编译器不知道B的类型信息,因此它会抛出错误('B':不是类或命名空间名称)。
  2. 通过B类的前向声明,编译器事先知道B的类型是否为Class与所有成员的实际声明。

  3. 在B类前向声明​​后运行以下代码。

  4. ///////////////

    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. 最终代码
    2. ////////////////////////

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

答案 3 :(得分:2)

当编译器开始读取代码时(通常是从顶部开始),它遇到了这一行:

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

然后编译器不理解这个B::是什么意思。即使您稍后在代码中定义了此类,但编译器也不知道。因此,如果定义稍后在代码中存在,那么练习前进类(class Name;)的声明通常是一件好事。

答案 4 :(得分:0)

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

答案 5 :(得分: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;
}

答案 6 :(得分:0)

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