在 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文件。