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的朋友
有几种方法可以解决这个问题。
- 以非成员身份编写一个或两个函数。如果需要,让他们成为两个 class 的朋友。
- 让整个 class 成为另一个 class 的朋友。如果这个权限太宽泛,请提取一个较小的 class 作为好友。
把两个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 中为您提供更多帮助...
我有以下 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的朋友
有几种方法可以解决这个问题。
- 以非成员身份编写一个或两个函数。如果需要,让他们成为两个 class 的朋友。
- 让整个 class 成为另一个 class 的朋友。如果这个权限太宽泛,请提取一个较小的 class 作为好友。
把两个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 中为您提供更多帮助...