0

I'm trying to develop a networking part in my basic game engine in C++, but I'm faced with a rather strange problem (it is for me).

I got a Singleton Networker class that handles the set-up of a socket (UDP) and will try to register the username the client provided to the server, returning a bool that represents if the username is already taken by a different player or not. The class itself does not handle the packets itself, I aim to use a Packethandler class for that.

The problem is that I don't want a client to be able to create a PacketHandler directly because the entire point of the Networker class is to provide some kind of interface for handling that. The first idea I had is 'make the constructor of Packethandler private and create a Singleton' but then ofcourse the client can still ask the instance. Then I quickly though 'well protected then' but Networker is not extending PacketHandler. Then I thought 'well let's make Networker a friend of PacketHandler'. All the info I found up till now seems to discourage Friend usage however, so I wonder: Is my plan for the simple networking part flawed thus facing me with an issue like this or is my problem the reason friend functionality exists in the first place? What is the take of you guys on this, do you have a much better idea?

Edit: code of my idea.

Packethandler.h

#ifndef FANCY_PACKET_HANDLER
#define FANCY_PACKET_HANDLER

#include <SFML/Network.hpp>

namespace fancy {
    namespace network {

        class PacketHandler 
        {
            friend class Networker;
        private:
            sf::IpAddress _hostAddress;
            sf::UdpSocket _socket;
            PacketHandler(std::string hostAdress);
        public:         
            ~PacketHandler();

            void sendPacket(const char* packet_data, const unsigned int packet_size);
            char* receivePacket();
        };

    }
}
#endif

Networker.h

#ifndef FANCY_NETWORKER
#define FANCY_NETWORKER

#include <SFML/Network.hpp>
#include <Engine/PacketHandler.h>

namespace fancy {
    namespace network {

        class Networker
        {       
        public:
            static Networker* instance();

            bool openUdpSocket(unsigned short port);

            bool registerUsername(char* username);
            char* receiveOnSocket();
        protected:
            Networker();
        private:
            static Networker* _instance;
            static PacketHandler* _packetHandler;

            const char* _username;

            sf::IpAddress _hostAddress;
            sf::UdpSocket _socket;
        };

    }
}

#endif
RB-Develop
  • 196
  • 1
  • 9
  • Do you really need the division of `Networker` and `PacketHandler`? – Marc Claesen May 08 '13 at 21:57
  • @MarcClaesen To be honest: not really, but I thought it would help my design and clarity of the code. I want to avoid getting a monolith Networker class sending the world, doing my dishes and wash my clothes. – RB-Develop May 08 '13 at 22:01
  • How about giving `PacketHandler` a private constructor and making `Networker` its friend? That way the client will have to poke your `Networker` singleton to get access to a `PacketHandler`. This way, you can make one or several handlers as you see fit. What downsides did you find with relation to friends in this context? – Marc Claesen May 08 '13 at 22:07
  • While making the whole class a friend is mostly discouraged, making a single friend method (or function) looks much neater to me. – nullptr May 08 '13 at 22:14
  • @MarcClaesen what you are saying is exactly what my idea was, but from what I can read people mostly try to avoid and use friend and instead make it one class. I was just wondering if my idea (and yours) was a good idea or if it was considered bad practice in this context. – RB-Develop May 08 '13 at 22:15
  • I added my 2 header files to illustrate my idea. Is that how the friend modifier is supposed to be used? – RB-Develop May 08 '13 at 22:22

1 Answers1

2

If you wish to provide an interface and hide all the implementation details, you'd better define a pure virtual class (e.g. Networker) which is visible to a user (say in .h-file), and write an implementation in a descendant class (e.g. NetworkerImpl) which is NOT visible to a user. You can then declare in the header file a function (or even a static method of the Networker class) like Networker *CreateNetworker(); (so the declaration is visible to a user), and then implement the function in .cc file along with your NetworkerImpl (so that the implementation is not visible to a user) like return new NetworkerImpl();.

nullptr
  • 11,008
  • 1
  • 23
  • 18
  • I want networker to be able to have it's own functionality so I try not to use a pure virtual class. Later on I want to see if I can make some general lobby system and extend the functionality so networker can handle the packet data in a very basic and generic way, which can be extended or even replaced by a client if he so wishes. – RB-Develop May 08 '13 at 22:24
  • I've added my 2 header files implementing the idea I had. Maybe it grants you a better insight in my, probably, vague explanation. – RB-Develop May 08 '13 at 22:28