Class 另一个 class 的方法朋友在两个单独的文件中
Class method friend of another class in two separate files
我的目标很简单 - 我想从另一个 class 的方法访问一个 class 的受保护成员。为此,我有以下 -
A.HPP
#ifndef A_HPP
#define A_HPP
#include "B.hpp"
using namespace std;
class A
{
protected:
int a;
public:
A();
~A(){};
friend void B::geta(A& ao);
};
inline A::A()
{
a = 2;
cout << a;
}
#endif
B.HPP
#ifndef B_HPP
#define B_HPP
using namespace std;
class A;
class B
{
protected:
int b;
public:
B();
~B(){};
void geta(A& ao);
};
inline B::B()
{
b = 1;
cout << b;
}
inline void B::geta(A& ao)
{
b = ao.a;
cout << b;
}
#endif
MAIN.CPP
#include <iostream>
#include "A.hpp"
#include "B.hpp"
int main()
{
A ao;
B bo;
bo.geta(ao);
return 0;
}
编译时出现以下错误。
我该如何解决这个问题?我在这里看到的大多数答案只是将所有 classes 放在一个文件中,并在适当的位置定义函数来实现这一点,但我需要将它们放在单独的文件中。
... but I need them in separate files.
将内联函数移到 #include
的 A.hpp
.
的单独 B.cpp
文件中
由于只是被视为转发的 class 声明 A
的声明在您开始在 B.hpp
中使用它时尚未完成,并且编译器对此有理有据地抱怨。
您仍然可以保留 inline
关键字,编译器会像往常一样将其视为提示。
草图如下:
B.hpp
#ifndef B_HPP
#define B_HPP
using namespace std;
class A;
class B
{
protected:
int b;
public:
B();
~B(){};
void geta(A& ao);
};
#endif
B.cpp
#include "B.hpp"
#include "A.hpp"
inline B::B()
{
b = 1;
cout << b;
}
inline void B::geta(A& ao)
{
b = ao.a; // <<<<<<<<<<<< here's the problem to be solved
cout << b;
}
这些问题和答案与您的问题非常相关:
- Resolve build errors due to circular dependency amongst classes
- Why are C++ inline functions in the header?
- C++ inline member function in .cpp file
选项 1:非内联
您当然可以将 B::geta
的定义移动到包含 A.hpp 的 B.cpp 文件并删除 inline
关键字。但这可能会降低编译器优化的可能性。
选项 2:奇怪的 #include
逻辑
只有当编译器看到 A
的前向声明、[=18= 的定义]、[=17= 的定义] 和 [=17= 的定义时,你的定义才能编译=14=], 都按这个顺序。所以如果你想在一个文件中定义 A
而在另一个文件中定义 B
,你需要让预处理器在文件之间来回切换。
A.hpp
// NO A_HPP include guard!
#ifdef INCLUDED_FROM_B_HPP
class A
{
protected:
int a;
public:
A();
~A(){};
friend void B::geta(A& ao);
};
inline A::A()
{
a = 2;
cout << a;
}
#else
# include "B.hpp"
#endif
B.hpp
#ifndef B_HPP
#define B_HPP
class A;
class B
{
protected:
int b;
public:
B();
~B(){};
void geta(A& ao);
};
#define INCLUDED_FROM_B_HPP
#include "A.hpp"
#undef INCLUDED_FROM_B_HPP
inline B::B()
{
b = 1;
cout << b;
}
inline void B::geta(A& ao)
{
b = ao.a;
cout << b;
}
#endif
所以现在如果一个文件 #include "B.hpp"
,预处理器将:
- 从B.hpp的第一部分输出
class A;
和B
的定义。
- 定义
INCLUDED_FROM_B_HPP
.
- 输出A.hpp中的定义。
- 清除
INCLUDED_FROM_B_HPP
的定义。
- 从B.hpp的第二部分输出
B
的内联成员的定义。
如果文件首先执行 #include "A.hpp"
,事情就有点棘手了:
- 因为没有设置
INCLUDED_FROM_B_HPP
,所以直接进入B.hpp。
- 从B.hpp的第一部分输出
class A;
和B
的定义。
- 定义
INCLUDED_FROM_B_HPP
.
- 当遇到B.hpp中间的
#include "A.hpp"
时,预处理器会递归回到A.hpp。但是这次由于定义了INCLUDED_FROM_B_HPP
,所以输出的是A.hpp. 的代码内容
- 清除
INCLUDED_FROM_B_HPP
的定义。
- 从B.hpp的第二部分输出
B
的内联成员的定义。
选项 3:friend class B;
与其将一个成员函数 B::geta
指定为好友,不如将 class 本身与声明 friend class B;
设为好友。现在A.hpp不需要包含B.hpp,所以不存在循环依赖问题。
从可以访问和不可以访问的角度来看,这并没有减少封装,因为通常任何可以修改 class B
任何部分的程序员也可以修改 B::geta
.但它确实打开了 "accidentally" 在 B
.
的其他成员中使用 A
的非 public 成员的可能性
选项 4:重构访问方法
A.hpp
#ifndef A_HPP
#define A_HPP
class B;
class A
{
protected:
int a;
public:
A();
~A(){};
class AccessForB {
private:
static int geta(A& aobj) { return aobj.a; }
friend class ::B;
};
};
inline A::A()
{
a = 2;
cout << a;
}
#endif
B.hpp
...
inline void B::geta(A& ao)
{
b = A::AccessForB::geta(ao);
cout << b;
}
此代码引入了一种新的封装:现在 class B
只能从成员 a
获取值,不能修改该值,也不能访问任何其他非 public A
的成员。可以酌情为其他成员添加其他访问器。为了允许修改成员,class 可以提供 "set" 访问器,或者提供 returns 引用的访问器。对于非 public 函数,class 可以提供仅传递给实际函数的包装函数。
B::geta
以外的 B
成员利用友谊仍然是事实,但现在输入 A::AccessForB::
真的不能被认为是意外。
我的目标很简单 - 我想从另一个 class 的方法访问一个 class 的受保护成员。为此,我有以下 -
A.HPP
#ifndef A_HPP
#define A_HPP
#include "B.hpp"
using namespace std;
class A
{
protected:
int a;
public:
A();
~A(){};
friend void B::geta(A& ao);
};
inline A::A()
{
a = 2;
cout << a;
}
#endif
B.HPP
#ifndef B_HPP
#define B_HPP
using namespace std;
class A;
class B
{
protected:
int b;
public:
B();
~B(){};
void geta(A& ao);
};
inline B::B()
{
b = 1;
cout << b;
}
inline void B::geta(A& ao)
{
b = ao.a;
cout << b;
}
#endif
MAIN.CPP
#include <iostream>
#include "A.hpp"
#include "B.hpp"
int main()
{
A ao;
B bo;
bo.geta(ao);
return 0;
}
编译时出现以下错误。
我该如何解决这个问题?我在这里看到的大多数答案只是将所有 classes 放在一个文件中,并在适当的位置定义函数来实现这一点,但我需要将它们放在单独的文件中。
... but I need them in separate files.
将内联函数移到 #include
的 A.hpp
.
B.cpp
文件中
由于只是被视为转发的 class 声明 A
的声明在您开始在 B.hpp
中使用它时尚未完成,并且编译器对此有理有据地抱怨。
您仍然可以保留 inline
关键字,编译器会像往常一样将其视为提示。
草图如下:
B.hpp
#ifndef B_HPP
#define B_HPP
using namespace std;
class A;
class B
{
protected:
int b;
public:
B();
~B(){};
void geta(A& ao);
};
#endif
B.cpp
#include "B.hpp"
#include "A.hpp"
inline B::B()
{
b = 1;
cout << b;
}
inline void B::geta(A& ao)
{
b = ao.a; // <<<<<<<<<<<< here's the problem to be solved
cout << b;
}
这些问题和答案与您的问题非常相关:
- Resolve build errors due to circular dependency amongst classes
- Why are C++ inline functions in the header?
- C++ inline member function in .cpp file
选项 1:非内联
您当然可以将 B::geta
的定义移动到包含 A.hpp 的 B.cpp 文件并删除 inline
关键字。但这可能会降低编译器优化的可能性。
选项 2:奇怪的 #include
逻辑
只有当编译器看到 A
的前向声明、[=18= 的定义]、[=17= 的定义] 和 [=17= 的定义时,你的定义才能编译=14=], 都按这个顺序。所以如果你想在一个文件中定义 A
而在另一个文件中定义 B
,你需要让预处理器在文件之间来回切换。
A.hpp
// NO A_HPP include guard!
#ifdef INCLUDED_FROM_B_HPP
class A
{
protected:
int a;
public:
A();
~A(){};
friend void B::geta(A& ao);
};
inline A::A()
{
a = 2;
cout << a;
}
#else
# include "B.hpp"
#endif
B.hpp
#ifndef B_HPP
#define B_HPP
class A;
class B
{
protected:
int b;
public:
B();
~B(){};
void geta(A& ao);
};
#define INCLUDED_FROM_B_HPP
#include "A.hpp"
#undef INCLUDED_FROM_B_HPP
inline B::B()
{
b = 1;
cout << b;
}
inline void B::geta(A& ao)
{
b = ao.a;
cout << b;
}
#endif
所以现在如果一个文件 #include "B.hpp"
,预处理器将:
- 从B.hpp的第一部分输出
class A;
和B
的定义。 - 定义
INCLUDED_FROM_B_HPP
. - 输出A.hpp中的定义。
- 清除
INCLUDED_FROM_B_HPP
的定义。 - 从B.hpp的第二部分输出
B
的内联成员的定义。
如果文件首先执行 #include "A.hpp"
,事情就有点棘手了:
- 因为没有设置
INCLUDED_FROM_B_HPP
,所以直接进入B.hpp。 - 从B.hpp的第一部分输出
class A;
和B
的定义。 - 定义
INCLUDED_FROM_B_HPP
. - 当遇到B.hpp中间的
#include "A.hpp"
时,预处理器会递归回到A.hpp。但是这次由于定义了INCLUDED_FROM_B_HPP
,所以输出的是A.hpp. 的代码内容
- 清除
INCLUDED_FROM_B_HPP
的定义。 - 从B.hpp的第二部分输出
B
的内联成员的定义。
选项 3:friend class B;
与其将一个成员函数 B::geta
指定为好友,不如将 class 本身与声明 friend class B;
设为好友。现在A.hpp不需要包含B.hpp,所以不存在循环依赖问题。
从可以访问和不可以访问的角度来看,这并没有减少封装,因为通常任何可以修改 class B
任何部分的程序员也可以修改 B::geta
.但它确实打开了 "accidentally" 在 B
.
A
的非 public 成员的可能性
选项 4:重构访问方法
A.hpp
#ifndef A_HPP
#define A_HPP
class B;
class A
{
protected:
int a;
public:
A();
~A(){};
class AccessForB {
private:
static int geta(A& aobj) { return aobj.a; }
friend class ::B;
};
};
inline A::A()
{
a = 2;
cout << a;
}
#endif
B.hpp
...
inline void B::geta(A& ao)
{
b = A::AccessForB::geta(ao);
cout << b;
}
此代码引入了一种新的封装:现在 class B
只能从成员 a
获取值,不能修改该值,也不能访问任何其他非 public A
的成员。可以酌情为其他成员添加其他访问器。为了允许修改成员,class 可以提供 "set" 访问器,或者提供 returns 引用的访问器。对于非 public 函数,class 可以提供仅传递给实际函数的包装函数。
B::geta
以外的 B
成员利用友谊仍然是事实,但现在输入 A::AccessForB::
真的不能被认为是意外。