在必须传回值时避免循环包含

avoiding circular inclusion when having to pass back values

本文关键字:循环 包含      更新时间:2023-10-16

在我有一个类与另一个类(如API)通信并从该类获得回调的情况下,处理循环包含的最佳方法是什么?

假设我有一个类

. h

class Requestor;
class Api
{
public:
    Api();
    void Request();
    int DoStuff();
 private:
    Requestor *p_rq_;
};

. cpp

#include "api.h"
#include "requestor.h"

Api::Api()
{
}

void Api::Request() {
    this->DoStuff();
}

void Api::ReturnRequestId( int id ) {
    this->p_rq->SetLastRequestId( id );
}

. h

class Api;
class Requestor
{
public:
    Requestor();
    void MakeRequest();
    void SetLastRequestId( int );
private:
    Api api_;
    int last_request_id_;
};

. cpp

#include "requestor.h"
#include "api.h"
Requestor::Requestor()
{
}

void Requestor::MakeRequest() {
    this->api_.Request();
}
void Requestor::SetLastRequestId( int id ) {
    this->last_request_id_ = id;
}

如果请求者发送请求,并且在某些时候api获得id并希望将其传递回请求者,我怎么能在不包括彼此的。h文件的情况下做到这一点,这将导致循环包含?假设我不能简单地让函数MakeRequest返回id,因为我不想保持这个线程,直到api得到id?

我对c++和编程相当陌生,所以我可能会错过明显的解决方案。由于我需要调用彼此的成员函数,我的理解是前向声明在这里不起作用。

另外,Api和Requestor应该是独立的库,所以我不能让它们成为一个类。

你有两个不同的问题,类之间的循环依赖和多个包含相同的头文件。

多重包含不仅仅是由简单的循环依赖引起的,就像你的情况一样。确保头文件在源文件中只包含一次的常用方法是使用include守卫。通常头文件看起来像这样:

#ifndef SOME_UNIQUE_NAME_
#define SOME_UNIQUE_NAME_
... header contents ...
#endif

这确保了无论头文件在源文件中被包含多少次(直接或间接),只有第一次实际包含它的内容,由于该宏,后续的包含被预处理器跳过。宏名必须是唯一的(原因很明显),它通常是头名后面跟着某种前缀,例如LIBNAME_MODULENAME_REQUESTOR_H_ .

一个广泛使用的替代方法,被大多数现代编译器支持,即使据我所知不是标准的,是在头开始使用pragma指令:

#pragma once
... header contents

你的另一个问题是类之间的循环依赖。这里你已经找到了一种绕过它的方法:你的Api类持有一个指向Requestor对象的指针,而不是对象本身。这允许您在Api.h中使用前向声明,而不包括完整的类定义。然而,Requestor类持有一个Api对象,而不仅仅是一个指针,所以在声明api_成员的地方必须有完整的Api类定义。因此,在这种情况下,您不能为Api类使用前向声明,您必须实际包含完整的定义。

使用

#ifndef __filex__  
#define __filex__  

在每个。h和

的开头
#endif

在结尾。

这样,.h文件只被读取一次