在必须传回值时避免循环包含
Posted
技术标签:
【中文标题】在必须传回值时避免循环包含【英文标题】:avoiding circular inclusion when having to pass back values 【发布时间】:2016-10-09 08:30:46 【问题描述】:在我有一个类与另一个类(如 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 应该是独立的库,所以我不能将它们归为一个类。
【问题讨论】:
您是否尝试过在Requestor.h
中包含Api.h
?您需要成员非指针的定义。不会有循环包含。
你可以在请求者中有一个指向 Api 的指针,而不是实例,在构造函数中创建它并在析构函数中删除它。或者,如果您想进行大量输入,请使用 auto_ptr。
@cup auto_ptr
已弃用,不应再使用。应使用shared_ptr
、unique_ptr
和weak_ptr
之一。
为了避免循环包含,您需要使用 include 保护或 #pragma once
。更多详情请见#pragma once vs include guards?
【参考方案1】:
你有两个不同的问题,你的类之间的循环依赖和同一个头文件的多次包含。
多重包含不仅仅是由简单的循环依赖引起的,就像你的情况一样。确保头文件在源文件中包含一次且仅包含一次的常用方法是使用包含保护。通常头文件是这样的:
#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
类使用前向声明,您实际上必须包含完整的定义。
【讨论】:
您不应在大写字母前添加单个_
。我建议不要使用__
。标准库对其库使用此约定,如果您使用相同的约定,您可能会弄乱代码。有关更多详细信息,请参阅Include guard conventions in C(虽然这是关于 c,但与 c++ 相同)您最好选择在Naming Include Guards 的答案中提到的 google 样式指南中推荐的那个。【参考方案2】:
使用
#ifndef __filex__
#define __filex__
在每个.h的开头和
#endif
最后。
这样,.h 文件只读一次
【讨论】:
以上是关于在必须传回值时避免循环包含的主要内容,如果未能解决你的问题,请参考以下文章
为啥 ofstream 在存储字符串的值时会避免前 4 个字符?