C++类互相引用

本文探讨了C++中两个类互相引用导致的问题,如何通过forward declarations和指针解决循环依赖,以及常见错误分析和改进方法。还介绍了Boost ASIO中的间接引用设计实例和避免编译错误的技巧。
摘要由CSDN通过智能技术生成

C++中经常会遇到一个问题:两个类之间互相用到对方。
问题: 这种是不是一个好的设计?
如果不是一种好的设计,有什么办法规避?
如果没办法规避,代码应该如何写来避免出现各种编译或运行问题?

参考:
https://stackoverflow.com/questions/4964482/how-to-create-two-classes-in-c-which-use-each-other-as-data

问题举例

File: bar.h

#ifndef BAR_H
#define BAR_H
#include "foo.h"
class bar {
public:
  foo getFoo();
protected:
  foo f;
};
#endif

File: foo.h

#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo {
public:
  bar getBar();
protected:
  bar b;
};
#endif

File: main.cpp

#include "foo.h"
#include "bar.h"

int
main (int argc, char **argv)
{
  foo myFoo;
  bar myBar;
}

$ g++ main.cpp

In file included from foo.h:3,
                 from main.cpp:1:
bar.h:6: error: ‘foo’ does not name a type
bar.h:8: error: ‘foo’ does not name a type

原因分析

两个类不能互相使用对方的类对象作为成员变量,因为这样会造成无限循环导致类对象的占用的空间无限大。
You cannot have two classes directly contain objects of the other type, since otherwise you’d need infinite space for the object (since foo has a bar that has a foo that has a bar that etc.)

解决方法

可以在类中使用对方类的指针作为成员变量,此时需要使用预先声明对方类。
请注意在两个头文件里面,并不会include对方的头文件。而是在两个类的cpp文件里再include对方类头文件。

You can indeed do this by having the two classes store pointers to one another, though. To do this, you’ll need to use forward declarations so that the two classes know of each other’s existence.

Notice that the two headers don’t include each other. Instead, they just know of the existence of the other class via the forward declarations. Then, in the .cpp files for these two classes, you can #include the other header to get the full information about the class. These forward declarations allow you to break the reference cycle of “foo needs bar needs foo needs bar.”
File: bar.h

#ifndef BAR_H
#define BAR_H

class foo; // Say foo exists without defining it.

class bar {
public:
  foo* getFoo();
protected:
  foo* f;
};
#endif 

File: foo.h

#ifndef FOO_H
#define FOO_H

class bar; // Say bar exists without defining it.

class foo {
public:
  bar* getBar();
protected:
  bar* f;
};
#endif

常见错误

常见错误1

该例子来自https://stackoverflow.com/questions/43578272/c-how-to-create-two-classes-using-each-other

class B;
class A {
public:
    A(B* b) : b(b) {}
    void Foo() {
        b->data++;
    }
    B* b;
};

class B {
public:
    void Boo() {
        A a(this);
        a.Foo();
    }
    int data = 0;
};

int main()
{
    B b;
    b.Boo();
}
  • 上面这段代码,编译的时候出现错误,“ b->data++;” 这一行报错信息为“error C2027: use of undefined type ‘B’”。
  • 出现这个错误的原因是:在类A中使用b->data++之前,只是对B做了forward declaration,而forward declaration只保证了类A知道类B的存在,但是这个时候类A还不知道类B的具体方法和成员,所以此时使用类B的方法或者成员就会报undefined。
  • 解决办法:把类A中foo函数的具体实现放到单独的一个.cpp文件中。

常见错误2

例子来自https://stackoverflow.com/questions/42004488/c-mutual-header-inclusion-and-forward-declarations
参数为类对象或者引用, 都需要complete type, 所以只有类声明是不行的。但是参数为const 引用,类可以是incomplete type的。

其他实现方法

参考来自boost::asio的一个chat_server官方例子,提供了一种两个类之间互相引用的另一种方法,是通过其中一个类加了纯虚父类作为接口来实现的。
https://www.boost.org/doc/libs/1_75_0/doc/html/boost_asio/example/cpp11/chat/chat_server.cpp

  1. chat_participant类是一个纯虚类;
  2. chat_session类继承自chat_participant类, chat_session类中有成员变量是类chat_room的引用;
  3. chat_room类中有类成员是chat_participant_ptr,也就是指向chat_session父类的指针;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值