在 C++ 中跨多个 类 正确使用友元函数
Using friend function correctly across multiple Classes in C++
我正在尝试使用好友功能。该函数应该是我拥有的所有 classes 的朋友。但是我收到多个错误,其中一些错误显示 incomplete type。以下是我拥有的文件:
main.cpp
#include <iostream>
#include "my_ClassA.h"
#include "my_ClassB.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
int main()
{
std::cout<<"Hello World";
my_namespace::my_ClassA object1;//this will do some computation and set everything up for object1
my_namespace::my_ClassB object2(object1);//this object2 will use object1 to further do other computation
my_namespace::my_ClassC object3(object2);
my_namespace::my_classD object4(object4);
//runComputation(object1, object2, object3, object4);
return 0;
}
my_ClassA.h
#pragma once
#include<string>
#include <vector>
//these three includes are for friend function BUT result in error incomplete type
#include "my_ClassB.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
/////////////////////////////////////////////
namespace my_namespace{
class my_ClassA{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
std::vector<std::string> get_vec();
};
void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
}
my_ClassA.cpp
#include "my_ClassA.h"
std::vector<std::string> my_namespace::my_ClassA::get_vec(){
return vec;
}
my_ClassB.h
#pragma once
#include<string>
#include <vector>
#include "my_ClassA.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
namespace my_namespace{
class my_ClassB{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
std::vector<std::string> get_vec();
my_ClassB(my_ClassA);
my_ClassB(){
;
}
};
}
my_ClassB.cpp
#include "my_ClassB.h"
std::vector<std::string> my_namespace::my_ClassB::get_vec(){
return vec;
}
my_namespace::my_ClassB::my_ClassB(my_ClassA temp_objA){
;
}
my_ClassC.h
#pragma once
#include<string>
#include <vector>
#include "my_ClassB.h"
#include "my_ClassA.h"
#include "my_ClassD.h"
namespace my_namespace{
class my_ClassC{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
my_ClassB objB;
public:
my_ClassC(my_ClassB);
std::vector<std::string> get_vec();
};
}
my_ClassC.cpp
#include "my_ClassC.h"
#include "my_ClassB.h"
std::vector<std::string> my_namespace::my_ClassC::get_vec(){
return vec;
}
my_namespace::my_ClassC::my_ClassC(my_ClassB temp_objB){
;
}
my_ClassD.h
#pragma once
#include<string>
#include <vector>
#include "my_ClassA.h"
#include "my_ClassB.h"
#include "my_ClassC.h"
namespace my_namespace{
class my_ClassD{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
my_ClassA objA;
public:
std::vector<std::string> get_vec();
};
}
my_ClassD.cpp
#include "my_ClassD.h"
std::vector<std::string> my_namespace::my_ClassD::get_vec(){
return vec;
}
我尝试使用 main.cpp 中每个 class 的 getter。但是我的一些 classes 有大尺寸向量、集合等。所以我不想一次又一次地复制它们。因此,我想直接在名为 运行Computation 的函数中访问 classes 的数据成员。该函数将把创建的对象作为引用,这样复制就不会在 main.cpp.
内部发生
我所拥有的是:首先,我创建了不同的对象,这些对象可以将先前创建的对象作为 main.cpp 中的输入。成功创建所有对象后,我想 运行 对这些对象进行一些计算。现在的问题是我可以使用在 main.cpp 文件中创建的对象的 getter 和 setter。但是对象内部有大向量和其他对象,因此每次我在使用 getter 的 for 循环中使用它们时,它们都会被复制。为了避免这种情况,我想创建一个可以将这些对象作为引用并避免复制的友元函数。我该如何解决这个问题?有没有更好的方法来实现这一目标?
PS:我知道ADL。当我写一个像 friend void runComputation(someobject&);
这样的友元声明然后在 class 之后使这个友元函数可见时会使用 ADL void runComputation(someobject&);
不要按值使用 return 以避免复制大向量,return const 引用访问数据或 non-const 引用修改。
例如,header:
#pragma once
#include<string>
#include <vector>
//these three includes are for friend function BUT result in error incomplete type
#include "my_ClassB.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
/////////////////////////////////////////////
namespace my_namespace{
class my_ClassA{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
// use this getter to modify inner data by reference
std::vector<std::string>& get_vec();
// use this getter to access data by const referenct
std::vector<std::string> const & get_vec() const;
};
void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
}
实施:
#include "my_ClassA.h"
std::vector<std::string>& my_namespace::my_ClassA::get_vec() {
return vec;
}
std::vector<std::string> const & my_namespace::my_ClassA::get_vec() const {
return vec;
}
您可能希望将 类 重构为函数调用链:
// class or struct which contains intermediate state
State state;
runComputation1(&state);
runComputation2(&state);
runComputation3(&state);
runComputation4(&state);
问题是由于不同文件的循环依赖。不要包含 headers,只需对不同的 class 参数使用前向声明即可解决问题。
创建一个 my_forwards.h
header 文件。它包含
命名空间my_namespace{
class my_ClassA;
class my_ClassB;
class my_ClassC;
class my_ClassD;
}
(或者只是在每个 header 文件的顶部手动写这个)。
现在根本不要在其他 header 中包含 my_ClassA.h
。如果 my_ClassB
中的函数 body 需要定义 my_ClassA
,请将其放在 .cpp
文件中而不是 header 中。
// my_forwards.h
namespace my_namespace {
class my_ClassA;
class my_ClassB;
class my_ClassC;
class my_ClassD;
void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
}
// my_ClassA.h
#pragma once
#include<string>
#include <vector>
#include "my_forwards.h"
namespace my_namespace{
class my_ClassA{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
std::vector<std::string> get_vec();
};
}
// my_ClassA.cpp
#include "my_ClassA.h"
// include other my_ClassX here if needed, after my_ClassA.h
// implementation of my_ClassA:
std::vector<std::string> my_namespace::my_Class::get_vec() {
return vec;
}
在某些情况下,这可能需要在 header 文件中声明 destructor/constructor,并在 cpp 文件中执行 my_ClassA::my_ClassA()=default;
。
现在,你的 my_ClassC
有一个 my_ClassB
类型的成员变量。在这种情况下,您必须在 my_ClassC.h
header 文件中 #include "my_ClassB.h"
,因为 my_ClassC
需要 my_ClassB
的定义。但在大多数情况下,前向声明就足够了,或者稍作修改(例如,将值参数更改为引用参数)就足够了,您不必 cross-include header文件。
我正在尝试使用好友功能。该函数应该是我拥有的所有 classes 的朋友。但是我收到多个错误,其中一些错误显示 incomplete type。以下是我拥有的文件:
main.cpp
#include <iostream>
#include "my_ClassA.h"
#include "my_ClassB.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
int main()
{
std::cout<<"Hello World";
my_namespace::my_ClassA object1;//this will do some computation and set everything up for object1
my_namespace::my_ClassB object2(object1);//this object2 will use object1 to further do other computation
my_namespace::my_ClassC object3(object2);
my_namespace::my_classD object4(object4);
//runComputation(object1, object2, object3, object4);
return 0;
}
my_ClassA.h
#pragma once
#include<string>
#include <vector>
//these three includes are for friend function BUT result in error incomplete type
#include "my_ClassB.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
/////////////////////////////////////////////
namespace my_namespace{
class my_ClassA{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
std::vector<std::string> get_vec();
};
void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
}
my_ClassA.cpp
#include "my_ClassA.h"
std::vector<std::string> my_namespace::my_ClassA::get_vec(){
return vec;
}
my_ClassB.h
#pragma once
#include<string>
#include <vector>
#include "my_ClassA.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
namespace my_namespace{
class my_ClassB{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
std::vector<std::string> get_vec();
my_ClassB(my_ClassA);
my_ClassB(){
;
}
};
}
my_ClassB.cpp
#include "my_ClassB.h"
std::vector<std::string> my_namespace::my_ClassB::get_vec(){
return vec;
}
my_namespace::my_ClassB::my_ClassB(my_ClassA temp_objA){
;
}
my_ClassC.h
#pragma once
#include<string>
#include <vector>
#include "my_ClassB.h"
#include "my_ClassA.h"
#include "my_ClassD.h"
namespace my_namespace{
class my_ClassC{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
my_ClassB objB;
public:
my_ClassC(my_ClassB);
std::vector<std::string> get_vec();
};
}
my_ClassC.cpp
#include "my_ClassC.h"
#include "my_ClassB.h"
std::vector<std::string> my_namespace::my_ClassC::get_vec(){
return vec;
}
my_namespace::my_ClassC::my_ClassC(my_ClassB temp_objB){
;
}
my_ClassD.h
#pragma once
#include<string>
#include <vector>
#include "my_ClassA.h"
#include "my_ClassB.h"
#include "my_ClassC.h"
namespace my_namespace{
class my_ClassD{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
my_ClassA objA;
public:
std::vector<std::string> get_vec();
};
}
my_ClassD.cpp
#include "my_ClassD.h"
std::vector<std::string> my_namespace::my_ClassD::get_vec(){
return vec;
}
我尝试使用 main.cpp 中每个 class 的 getter。但是我的一些 classes 有大尺寸向量、集合等。所以我不想一次又一次地复制它们。因此,我想直接在名为 运行Computation 的函数中访问 classes 的数据成员。该函数将把创建的对象作为引用,这样复制就不会在 main.cpp.
内部发生我所拥有的是:首先,我创建了不同的对象,这些对象可以将先前创建的对象作为 main.cpp 中的输入。成功创建所有对象后,我想 运行 对这些对象进行一些计算。现在的问题是我可以使用在 main.cpp 文件中创建的对象的 getter 和 setter。但是对象内部有大向量和其他对象,因此每次我在使用 getter 的 for 循环中使用它们时,它们都会被复制。为了避免这种情况,我想创建一个可以将这些对象作为引用并避免复制的友元函数。我该如何解决这个问题?有没有更好的方法来实现这一目标?
PS:我知道ADL。当我写一个像 friend void runComputation(someobject&);
这样的友元声明然后在 class 之后使这个友元函数可见时会使用 ADL void runComputation(someobject&);
不要按值使用 return 以避免复制大向量,return const 引用访问数据或 non-const 引用修改。
例如,header:
#pragma once
#include<string>
#include <vector>
//these three includes are for friend function BUT result in error incomplete type
#include "my_ClassB.h"
#include "my_ClassC.h"
#include "my_ClassD.h"
/////////////////////////////////////////////
namespace my_namespace{
class my_ClassA{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
// use this getter to modify inner data by reference
std::vector<std::string>& get_vec();
// use this getter to access data by const referenct
std::vector<std::string> const & get_vec() const;
};
void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
}
实施:
#include "my_ClassA.h"
std::vector<std::string>& my_namespace::my_ClassA::get_vec() {
return vec;
}
std::vector<std::string> const & my_namespace::my_ClassA::get_vec() const {
return vec;
}
您可能希望将 类 重构为函数调用链:
// class or struct which contains intermediate state
State state;
runComputation1(&state);
runComputation2(&state);
runComputation3(&state);
runComputation4(&state);
问题是由于不同文件的循环依赖。不要包含 headers,只需对不同的 class 参数使用前向声明即可解决问题。
创建一个 my_forwards.h
header 文件。它包含
命名空间my_namespace{ class my_ClassA; class my_ClassB; class my_ClassC; class my_ClassD; } (或者只是在每个 header 文件的顶部手动写这个)。
现在根本不要在其他 header 中包含 my_ClassA.h
。如果 my_ClassB
中的函数 body 需要定义 my_ClassA
,请将其放在 .cpp
文件中而不是 header 中。
// my_forwards.h
namespace my_namespace {
class my_ClassA;
class my_ClassB;
class my_ClassC;
class my_ClassD;
void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
}
// my_ClassA.h
#pragma once
#include<string>
#include <vector>
#include "my_forwards.h"
namespace my_namespace{
class my_ClassA{
friend void runComputation(my_ClassA&,my_ClassB&,my_ClassC&,my_ClassD&);
private:
std::string name;
std::vector<std::string> vec;
public:
std::vector<std::string> get_vec();
};
}
// my_ClassA.cpp
#include "my_ClassA.h"
// include other my_ClassX here if needed, after my_ClassA.h
// implementation of my_ClassA:
std::vector<std::string> my_namespace::my_Class::get_vec() {
return vec;
}
在某些情况下,这可能需要在 header 文件中声明 destructor/constructor,并在 cpp 文件中执行 my_ClassA::my_ClassA()=default;
。
现在,你的 my_ClassC
有一个 my_ClassB
类型的成员变量。在这种情况下,您必须在 my_ClassC.h
header 文件中 #include "my_ClassB.h"
,因为 my_ClassC
需要 my_ClassB
的定义。但在大多数情况下,前向声明就足够了,或者稍作修改(例如,将值参数更改为引用参数)就足够了,您不必 cross-include header文件。