As a follow up to an older question of mine, I wish to implement a client-server mockup simulation, where the client initiates a sequence of actions that involve calling methods on the server, which, in turn, can call methods on the client (let's ignore the issue that the stack may blow up).
More specifically, since I want to split the implementation from the definition, I will have server.h and server.cpp for the Server class and client.h and client.cpp for the Client class. Since Server holds a reference to Client and calls methods from it, it needs to #include "client.h"
. Also, Client holds a reference to Server and calls methods from it, it needs to #include "server.h"
. At this point, even if I use header guards in both server.h and client.h, it still messes up (yeah, it's expected) so I decided to forward-declare the Server class in client.h and the Client class in server.h. Unfortunately, this is not enough to solve the issue, because I'm also calling methods from the two classes, so I managed to make it compile & run (properly, as far as I can tell), by including server.h in client.cpp and client.h in server.cpp.
Does the above "hack" sound reasonable? Should I expect some unforeseen consequences? Is there any "smarter" way to do this without having to implement a proxy class?
Here's a rudimentary sample of how the implementation will look like:
file client.h:
#ifndef CLIENT_H
#define CLIENT_H
#include <iostream>
#include <memory>
class Server;
class Client
{
private:
std::shared_ptr<const Server> server;
public:
Client () {}
void setServer (const std::shared_ptr<const Server> &server);
void doStuff () const;
void doOtherStuff () const;
};
#endif
file client.cpp:
#include "client.h"
#include "server.h"
void Client::setServer (const std::shared_ptr<const Server> &server)
{
this->server = server;
}
void Client::doStuff () const
{
this->server->doStuff();
}
void Client::doOtherStuff () const
{
std::cout << "All done!" << std::endl;
}
file server.h:
#ifndef SERVER_H
#define SERVER_H
#include <iostream>
#include <memory>
class Client;
class Server
{
private:
std::weak_ptr<const Client> client;
public:
Server () {}
void setClient (const std::weak_ptr<const Client> &client);
void doStuff () const;
};
#endif
file sever.cpp:
#include "server.h"
#include "client.h"
void Server::setClient (const std::weak_ptr<const Client> &client)
{
this->client = client;
}
void Server::doStuff () const
{
this->client.lock()->doOtherStuff();
}
file main.cpp:
#include <iostream>
#include <memory>
#include "client.h"
#include "server.h"
int main ()
{
std::shared_ptr<Client> client(new Client);
std::shared_ptr<Server> server(new Server);
client->setServer(server);
server->setClient(client);
client->doStuff();
return 0;
}