【问题标题】:How to use circularly dependent classes in C++?如何在 C++ 中使用循环依赖类?
【发布时间】:2012-02-27 07:45:47
【问题描述】:

此代码未编译。

我可以做哪些修改才能达到预期的效果?

ClassOne.h

#ifndef _CLASS_ONE_
#define _CLASS_ONE_

#include <string>
#include "ClassTwo.h"

class ClassTwo;

class ClassOne
{
private:
    string message;     
    friend ClassTwo;
    ClassTwo m_ClassTwo;

public:
    ClassOne();
    void Display();
};

#endif

ClassTwo.h

#ifndef _CLASS_TWO_
#define _CLASS_TWO_

#include <string>
#include "ClassOne.h"

class ClassOne;

class ClassTwo
{
private:
    string message;
    friend ClassOne;
    ClassOne m_ClassOne;

public:
    ClassTwo();
    void Display();
};

#endif

ClassOne.cpp

#include "ClassOne.h"
#include "ClassTwo.h"
#include <iostream>

ClassOne :: ClassOne()
{
    std::cout<<"ClassOne()...called\n";
    this->m_ClassTwo.message = "ClassOne - Message\n";
}

void ClassOne :: Display()
{
    std::cout<<this->m_ClassTwo.message;
}

ClassTwo.cpp

#include "ClassTwo.h"
#include "ClassOne.h"
#include <iostream>

ClassTwo :: ClassTwo()
{
    std::cout<<"ClassTwo()...called\n";
    this->m_ClassOne.message = "ClassTwo - Message\n";
}

void ClassTwo :: Display()
{
    std::cout<<this->m_ClassOne.message;
}

main.cpp

#include "ClassOne.h"
#include "ClassTwo.h"

int main()
{
    ClassOne one;
    one.Display();

    ClassTwo two;
    two.Display();
}

错误信息

1   error C2146: syntax error : missing ';' before identifier 'message'
2   error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
3   error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
4   error C2079: 'ClassTwo::m_ClassOne' uses undefined class 'ClassOne'
5   error C2146: syntax error : missing ';' before identifier 'message'
6   error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
7   error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
8   error C2039: 'message' : is not a member of 'ClassTwo'
9   error C2039: 'message' : is not a member of 'ClassTwo'
10  error C2146: syntax error : missing ';' before identifier 'message'
11  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
12  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
13  error C2079: 'ClassOne::m_ClassTwo' uses undefined class 'ClassTwo'
14  error C2146: syntax error : missing ';' before identifier 'message'
15  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
16  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
17  error C2039: 'message' : is not a member of 'ClassOne'
18  error C2039: 'message' : is not a member of 'ClassOne'
19  error C2146: syntax error : missing ';' before identifier 'message'
20  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
21  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
22  error C2079: 'ClassTwo::m_ClassOne' uses undefined class 'ClassOne'
23  error C2146: syntax error : missing ';' before identifier 'message'
24  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
25  error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

【问题讨论】:

  • 类或函数可以声明为friend,类的特定实例不能声明为friend,一旦你有一个对象作为你的类的成员,它就会遵守由访问说明符&你不能使用friend绕过这些规则。

标签: c++ class cross-reference


【解决方案1】:

您永远无法编译该代码。您描述了一个系统,其中类型 A 包含类型 B,类型 B 包含类型 A。因此,类型 A 和 B 都递归地无限地包含自己,这是不可能的。你必须从根本上重新设计你的代码来消除这个问题。

另外,您的friend 语法错误。

【讨论】:

  • 他当然可以编译该代码,只需稍作调整即可。他所需要的只是前向声明并将成员更改为引用或指针。
  • @martiert:好像这不是相当根本的变化。
  • @Saqib:循环包含成员变量肯定是不可能的。
【解决方案2】:

如前所述,您需要转发声明 ClassOne 或 ClassTwo 中的至少一个。

因此你的 ClassOne.h 可能看起来像:

#ifndef _CLASS_ONE_
#define _CLASS_ONE_

#include <string>

class ClassTwo;

class ClassOne
{
private:
    string message;
    ClassTwo* m_ClassTwo;

public:
    ClassOne();
    void Display();
};

#endif

如您所见,我们声明了 ClassTwo,但不包含它。我们基本上只告诉编译器是的,我们确实有一个 ClassTwo,但我们现在并不关心它包含什么。

还请查看您的 ClassTwo 成员,这现在是一个指针。原因是成员会要求编译器知道对象的大小,我们目前不知道它是什么。因此,您需要一个指针或一个参考。

接下来,在您的 ClassOne.cpp 中,需要包含 ClassTwo.h,以获取该类的功能和大小。

不过有几点: 使用前向声明,您不能从 ClassTwo 继承,在头文件中使用前向类的方法(编译器如何知道存在哪些方法?)使用前向类定义函数或方法,即您必须通过引用传递或传递一个指针。

【讨论】:

  • 我需要知道一件事,不使用指针是否可以实现同样的事情?如果我想将普通对象声明为私有变量,它会起作用吗?如果不是,为什么?
  • 您可以通过使用引用获得相同的结果,但在您的情况下似乎不起作用,因为它会被传入。它也有点难看,因为您假设您知道传入的对象,因此指针/智能指针是要走的路。成员不起作用的原因是编译器需要对象的大小。要知道大小,编译器需要查看类来计算大小,因为这取决于类的成员。
  • 它需要成员大小的原因是对象的大小将取决于成员的大小。但是对于指针/引用,对象中使用的大小将不取决于指针指向的大小,因为指针具有固定大小。
【解决方案3】:

1) 使用前向声明:

添加

class ClassTwo;

到 ClassOne.h

class ClassTwo;

到 ClassTwo.h

2) 您需要使用 operator new 动态创建成员变量(或至少其中一个),或者如果您愿意,可以使用智能指针之一,例如来自 boost 库的 boost::shared_ptrstd::shared_ptr如果您使用 C++11,则来自标准库。

【讨论】:

  • @Saqib 请参见第 2 部分)——您需要将变量转换为指针。
  • @DeadMG 描述了——你不能让对象递归地成为彼此的一部分。如果使用指针,对象被分配在不同的位置(准确地说是在堆中),并且您只存储指向对象的指针。
猜你喜欢
  • 2013-10-21
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 2018-07-17
  • 2020-03-19
  • 1970-01-01
  • 2015-06-24
相关资源
最近更新 更多