为什么使用前向声明来避免循环依赖?编译器如何知道这一点?

时间:2019-04-16 20:46:39

标签: c++ oop compiler-construction dependencies circular-dependency

我不确定我是否问过最明确的问题,因此请原谅我是否出于观点。

在编程中,我通常遵循这样的哲学:如果一个库属于.cpp文件,那么它应该属于.hpp文件。但是,对于OOP,这不一定适用。我想出了一个非常小的例子:

Class1来源:

#include "class1.hpp"

int Class1::getOther(Class2 *obj)
{
  return obj->get();
}

void Class1::setOther(Class2 *obj, int val)
{
  obj->set(val);
}

Class1标头:

#ifndef CLASS_1_HPP
#define CLASS_1_HPP

#include "class2.hpp"

class Class1
{
  public:
    int getOther(Class2 *obj);
    void setOther(Class2 *obj, int val);

    int get() const { return value; }
    void set(int val) { value = val; }
  private:
    int value;
};

#endif

Class2来源:

#include "class1.hpp" // Placed here instead of class2.hpp
#include "class2.hpp"

int Class2::getOther(Class1 *obj)
{
  return obj->get();
}

void Class2::setOther(Class1 *obj, int val)
{
  obj->set(val);
}

Class2标头:

#ifndef CLASS_2_HPP
#define CLASS_2_HPP

class Class1; // Forward Declaration

class Class2
{
  public:
    int getOther(Class1 *obj);
    void setOther(Class1 *obj, int val);

    int get() const { return value; }
    void set(int val) { value = val; }
  private:
    int value;
};


#endif

主要:

#include <iostream>

#include "class1.hpp"

int main()
{
  Class1 *A = new Class1;
  Class2 *B = new Class2;

  A->setOther(B,15);
  A->set(A->getOther(B));

  std::cout << "A: " << B->getOther(A) << " B: " << A->getOther(B) << std::endl;

  delete A;
  delete B;
}

这是一个简单的示例,不一定要相互依赖。但是,为了编译该代码,我们必须将class1.hppclass2.hpp移到class2.cpp。然后要解决此问题,我们在Class1中创建Class2的前向声明。由于两个标头不会冲突,因此摆脱了循环依赖关系,Class1Class2现在将可以安全地相互了解。

编程时,我将头文件和源文件都视为一个完整的对象。或者,该源文件只是头文件的扩展,并且扩展了头文件的所有定义。在这种情况下,我要做的是创建一个知道Class1Class2的驱动程序类,并控制它们。

此实现如何避免循环依赖?编译器如何编译它而不捕获任何可能的循环依赖关系?最后,什么时候需要以这种方式使用前向声明?

0 个答案:

没有答案