gpt4 book ai didi

c++ - 两个单独文件中另一个类的类方法 friend

转载 作者:搜寻专家 更新时间:2023-10-31 02:05:12 24 4
gpt4 key购买 nike

我的目标很简单——我想从另一个类的方法访问一个类的 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;
}

当我编译它时,出现以下错误。

error

我该如何解决这个问题?我在这里看到的大多数答案只是将所有类放在一个文件中,并在适当的位置定义函数来实现这一点,但我需要将它们放在单独的文件中。

最佳答案

选项 1:非内联

您当然可以将 B::geta 的定义移动到包含 A.hpp 的 B.cpp 文件中,并删除 inline 关键字。但这可能会降低编译器优化的可能性。

选项 2:奇怪的 #include 逻辑

只有当编译器看到 A 的前向声明、B 的定义、A 的定义时,你的定义才能编译>,以及 B::geta 的定义,全部按此顺序。所以如果你想在一个文件中定义 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",预处理器将:

  1. 从B.hpp的第一部分输出class A;B的定义。
  2. 定义 INCLUDED_FROM_B_HPP
  3. 输出A.hpp中的定义。
  4. 清除 INCLUDED_FROM_B_HPP 的定义。
  5. 从B.hpp的第二部分输出B的内联成员的定义。

如果一个文件首先执行#include "A.hpp",事情就有点棘手了:

  1. 因为INCLUDED_FROM_B_HPP没有设置,直接进入B.hpp。
  2. 从B.hpp的第一部分输出class A;B的定义。
  3. 定义 INCLUDED_FROM_B_HPP
  4. 当遇到B.hpp 中间的#include "A.hpp" 时,预处理器会递归回到A.hpp。但是这次由于定义了INCLUDED_FROM_B_HPP,所以输出的是A.hpp的代码内容。
  5. 清除 INCLUDED_FROM_B_HPP 的定义。
  6. 从B.hpp的第二部分输出B的内联成员的定义。

选项 3: friend 类 B;

与其将一个成员函数 B::geta 指定为 friend,不如通过声明 friend class B; 与类本身成为 friend 。现在A.hpp不需要包含B.hpp,所以不存在循环依赖问题。

从访问权限的角度来看,这并没有减少封装,因为通常任何可以修改 class B 任何部分的程序员也可以修改 B::geta.但它确实打开了在 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中获取值,不能修改那个值,也不能访问A 的任何其他非公共(public)成员。可以酌情为其他成员添加其他访问器。为了允许修改成员,该类可以提供“set”访问器,或者提供返回引用的访问器。对于非公共(public)函数,该类可以提供仅传递给实际函数的包装函数。

B 的成员而不是 B::geta 仍然有可能利用友元,但现在输入 A::AccessForB: : 不能真正认为是意外。

关于c++ - 两个单独文件中另一个类的类方法 friend ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52324788/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com