C++ 中的双边友元函数:如何编译?

Bilateral friend functions in C++: how to make it compile?

我有以下 C++ 文件:

A.h


#ifndef A_H
#define A_H

#include "B.h"

class A
{
    private:
        int m_a;
    public:
        A();

        void a(const B &b);

    friend void B::b(const A &a);
};

#endif // A_H

A.cpp


#include "A.h"
#include "B.h"
#include 

A::A()
{
    m_a = 100;
}

void A::a(const B &b)
{
    std::cout << b.m_b << ".\n";
}

B.h


#ifndef B_H
#define B_H

class A;

class B
{
    private:
        int m_b;
    public:
        B();
        void b(const A &a);

    friend void A::a(const B &b); // error: invalid use of incomplete type 'class A'
};

#endif // B_H

B.cpp


#include "B.h"
#include 
#include "A.h"

B::B()
{
    this->m_b = 101;
}

void B::b(const A &a)
{
    std::cout << a.m_a << ".\n";
}

当我尝试编译它时,它给了我:

error: invalid use of incomplete type 'class A'.

我应该如何解决这个问题?

您使用的是未知类型:

friend void A::a(const B &b);

编译器只知道classA​​存在,除此之外一无所知。 您可以将整个 class A 声明为朋友:

friend class A;

实际上在你的情况下,你正在创建循环依赖。

前向声明通常会避免这种情况,但据我所知,C++ 不允许我们对成员函数进行前向声明,所以现在对我来说这似乎是不可能的。

但是当您将 class 声明为 friend 时,可以打破循环依赖。

a.h

#ifndef A_H
#define A_H

#include "b.h"

class B;

class A
{
    private:
        int m_a;
    public:
        A();

        void a(const B &b);

    friend class B;
};

#endif // A_H

a.cpp

#include "a.h"
#include "b.h"
#include <iostream>

A::A()
{
    m_a = 100;
}

void A::a(const B &b)
{
    std::cout << b.m_b << ".\n";
}

b.h

#ifndef B_H
#define B_H

class A;

class B
{
    private:
        int m_b;
    public:
        B();
        void b(const A &a);

    friend class A;
};

#endif // B_H

b.cpp

#include "b.h"
#include "a.h"
#include <iostream>

B::B()
{
    this->m_b = 101;
}

void B::b(const A &a)
{
    std::cout << a.m_a << ".\n";
}

不可能有B的成员函数是A的朋友,A的成员函数是B的朋友

有几种方法可以解决这个问题。

  1. 以非成员身份编写一个或两个函数。如果需要,让他们成为两个 class 的朋友。
  2. 让整个 class 成为另一个 class 的朋友。如果这个权限太宽泛,请提取一个较小的 class 作为好友。
  3. 把两个class都变成class模板(模板参数无关紧要)。

    enum unit {u};
    
    template <unit X> class A;
    
    template <unit X> class B
    {
        static void foo() {}
        static void bar() { A<X>::foo(); }
        friend void A<X>::bar();
    };
    
    template <unit X> class A
    {
        static void foo() {}
        static void bar() { B<X>::foo(); }
        friend void B<X>::bar();
    };
    
    using AX = A<u>;
    using BX = B<u>;
    

您正在尝试设置循环依赖。这是一件很难处理的事情,在很多用例中都是被禁止的。在 C++ 中,规则是您可以在 声明 后立即使用任何对象,即使稍后对其进行了完整定义。问题在于成员仅由 class 的定义声明。所以如果一个class(比如B)需要使用它的定义members另一个class(比如A),那么A必须在B之前定义。因为你不能同时在 B 之前定义 A 和在 A 之前定义 B,你将无法在 C++ 中实现你想要的。

如果您发现自己试图将 A 的成员设置为 B 中的朋友,并将 B 的成员设置为 A 中的朋友,那么您遇到了一般设计问题。如果有意义(从模型的角度来看),可以通过将一个完整的 class 作为朋友(这是@zmb 的回答)或将成员函数更改为非成员来解决。但我强烈建议您退后一步,尝试构建一个分层模型而不是循环模型。不幸的是,它变成了一个设计问题而不是一个编程问题,所以我恐怕无法在 SO 中为您提供更多帮助...