我的目标很简单-我想从另一个类的方法访问一个类的 protected 成员。为此,我有以下内容-
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;
}
当我对此进行编译时,出现以下错误。
我该如何解决?我在这里看到的大多数答案只是将所有类放在一个文件中,并在适当的位置定义函数以实现此目的,但我需要将它们放在单独的文件中。
最佳答案
选项1:非内联
当然,您可以将B::geta
的定义移动到包含A.hpp的B.cpp文件中,并删除inline
关键字。但这可能会使编译器优化的可能性降低。
选项2:奇怪的#include
逻辑
仅当编译器看到A
的前向声明,B
的定义,A
的定义和B::geta
的定义按顺序排列时,您的定义才可以编译。因此,如果要在一个文件中定义A
,在另一个文件中定义B
,则需要使预处理器在文件之间来回切换。
丙型肝炎
// 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
乙型肝炎
#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"
,则预处理器将:class A;
和B
的定义。 INCLUDED_FROM_B_HPP
。 INCLUDED_FROM_B_HPP
的定义。 B
的内联成员的定义。 如果文件首先执行
#include "A.hpp"
,则事情会有些棘手:INCLUDED_FROM_B_HPP
,因此请立即进入B.hpp。 class A;
和B
的定义。 INCLUDED_FROM_B_HPP
。 #include "A.hpp"
时,预处理器将递归返回A.hpp。但是这一次因为定义了INCLUDED_FROM_B_HPP
,所以它输出A.hpp的代码内容。 INCLUDED_FROM_B_HPP
的定义。 B
的内联成员的定义。 选项3:
friend class B;
与其仅向 friend 指定一个成员函数
B::geta
,不如将类本身与声明friend class B;
成为 friend 。现在,A.hpp不需要包含B.hpp,因此不存在循环依赖问题。从什么访问是可能的 Angular 来看,这并不会减少封装,因为通常任何可以修改
class B
的任何部分的程序员都可以修改B::geta
。但是它确实在A
的其他成员中使用B
的非公开成员“偶然地”打开了可能性。选项4:重构访问方法
丙型肝炎
#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
乙型肝炎
...
inline void B::geta(A& ao)
{
b = A::AccessForB::geta(ao);
cout << b;
}
这段代码引入了一种新的封装形式:现在
class B
只能从成员a
中获取值,不能修改该值,并且不能访问A
的任何其他非公共(public)成员。可以根据需要为其他成员添加其他访问者。为了允许修改成员,该类可以提供“设置”访问器,也可以提供返回引用的访问器。对于非公共(public)函数,该类可以提供仅传递给实际函数的包装器函数。的确,除
B
之外的其他B::geta
成员也有可能利用友谊,但是现在输入A::AccessForB::
确实不能算是偶然。