-2

what is the best way to handle circular inclusions in the situation where I have a class that communicates with another class, like an API and gets callbacks from that class.

Assume I have a class

.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 );

}

and

.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;

}

In case requestor sends a request and at some point the api gets an id and wants to pass that back to the requestor, how can I do that without including each others .h file which would lead to circular inclusion? Assume that I cant simply have the function MakeRequest return the id as I dont want to hold that thread until api gets the id?

I am fairly new to c++ and programming, so I may miss the obvious solution. Since I need to call member functions of each other, it is my understanding that forward declaration does not work here.

Also, Api and Requestor should be separate libraries, so I can't make them one class.

chrise
  • 3,415
  • 2
  • 21
  • 58
  • Have you tried including `Api.h` in `Requestor.h`? You need the definiton for the member non-pointer. There will be no circular inclusion. – LogicStuff Oct 09 '16 at 08:39
  • Instead of an instance, you could have a pointer to Api in requestor, create it in the constructor and delete it in the destructor. Or, if you want to do a lot of typing, use an auto_ptr. – cup Oct 09 '16 at 08:55
  • @cup `auto_ptr` is deprecated and should not be used anymore. Instead one of `shared_ptr`, `unique_ptr` and `weak_ptr` should be used. – t.niese Oct 09 '16 at 09:00
  • To avoid circual inclusion you would need to use include guards or `#pragma once` . See [#pragma once vs include guards?](http://stackoverflow.com/questions/1143936) for more details – t.niese Oct 09 '16 at 09:11

2 Answers2

1

Use

#ifndef __filex__  
#define __filex__  

At the beginning of each .h and

#endif

At the end.

This way, the .h file is read only once

t.niese
  • 32,069
  • 7
  • 56
  • 86
karim_g
  • 115
  • 11
1

You have two different issues, circular dependency between your classes and multiple inclusion of the same header file.

Multiple inclusion is not caused only by simple circular dependencies, like in your case. The usual way to make sure a header is included once and only once in a source file is to use include guards. Normally a header file looks like this:

#ifndef SOME_UNIQUE_NAME_
#define SOME_UNIQUE_NAME_

... header contents ...

#endif

This ensures that no matter how many times a header gets included in a source file (either directly or indirectly), only the first time its contents are actually included, subsequent inclusions are skipped by the preprocessor due to that macro. The macro name must be unique (for obvious reasons), and it is usually some kind of prefix followed by the header name, e.g. LIBNAME_MODULENAME_REQUESTOR_H_.

A widely used alternative, supported by most modern compilers even if not standard as far as I know, is to use a pragma directive at the beginning of the header:

#pragma once

... header contents

Your other issue is circular dependency between your classes. Here you've already found one way to go around it: your Api class holds a pointer to a Requestor object and not the object itself. This allows you to use a forward declaration in Api.h and not include the full class definition. The Requestor class however holds an Api object, not just a pointer, so the full Api class definition must be available at the point where the api_ member is declared. So you can't use a forward declaration for the Api class in this case, you must actually include the full definition.

Ionut
  • 5,048
  • 1
  • 14
  • 17
  • 1
    You should not add a single `_` in front of a uppercase letter. I would suggest to not even use `__`. The standard library uses this convention for its libraries and you can mess-up the code if you use the same convention. See for more details [Include guard conventions in C](http://stackoverflow.com/questions/17307540) (while this is about c it is the same with c++) you better choose the one recommended in the google's style guide mention in the answer to [Naming Include Guards](http://stackoverflow.com/a/4867672/1960455). – t.niese Oct 09 '16 at 10:28