我的目标很简单-我想从另一个类的方法访问一个类的受保护成员。为此,我有以下内容-
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;
}
当我编译它时,出现以下错误。
该如何解决?我在这里看到的大多数答案只是将所有类放在一个文件中,并在适当的位置定义函数以实现此目的,但我需要将它们放在单独的文件中。
答案 0 :(得分:1)
...但是我需要在单独的文件中
将内联函数移到B.cpp
的{{1}}所在的单独的#include
文件中。
就像被视为转发类声明A.hpp
的声明那样,在您开始在A
中使用它的时候还不完整,编译器理所当然地对此表示抱怨。
您仍然可以保留B.hpp
关键字,编译器将像往常一样将其视为提示。
这是草图:
inline
#ifndef B_HPP
#define B_HPP
using namespace std;
class A;
class B
{
protected:
int b;
public:
B();
~B(){};
void geta(A& ao);
};
#endif
这些问题和答案与您的问题非常相关:
答案 1 :(得分:1)
您当然可以将B::geta
的定义移动到包含A.hpp的B.cpp文件中,并删除inline
关键字。但这可能会使编译器优化的可能性降低。
#include
逻辑仅当编译器看到A
的前向声明,B
的定义,A
的定义和{{1的定义时, }},按此顺序进行。因此,如果要在一个文件中定义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"
,因此请立即进入B.hpp。INCLUDED_FROM_B_HPP
和class A;
的定义。B
。INCLUDED_FROM_B_HPP
时,预处理器将递归返回A.hpp。但是这一次因为定义了#include "A.hpp"
,所以它输出A.hpp的代码内容。INCLUDED_FROM_B_HPP
的定义。INCLUDED_FROM_B_HPP
的内联成员的定义。B
与其仅向朋友指定一个成员函数friend class B;
,不如将类本身与声明B::geta
成为朋友。现在,A.hpp不需要包含B.hpp,因此不存在循环依赖问题。
从什么访问是不可能的角度来看,这并不会减少封装,因为通常可以修改friend class B;
的任何部分的程序员也可以修改class B
。但这确实为在B::geta
的其他成员中使用A
的非公共成员打开了“偶然”的可能性。
B
...
#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
以外的B
成员有可能利用友谊,但现在输入B::geta
并不能算是偶然。