简体   繁体   中英

How to best make network functions accessible from other classes?

C++ novice here.

I'm trying to teach myself C++ by working on a project to create a Robot that gets commands from and sends telemetry back to a remote server.

I have a TcpCom class on the Robot which contains the socket connection and public functions to send messages and receive messages from the server:

#ifndef TCPCOM_H
#define TCPCOM_H
#define BOOST_DATE_TIME_NO_LIB
#include <boost/asio.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <deque>
#include <mutex>
#include "COM.h"

class TcpCom : public COM
{

    public:
        TcpCom() : io_srv(), tcpSocket(io_srv), remoteHost(""), remotePort(""), connectedToRemoteHost(false), outboundMsgQueue(), outboundMsgQueueMutex(),
        messagesInOutboundMsgQueue(0), incomingMsgQueue(), incomingMsgQueueMutex()
        {}
        int initialize();
        void connectToRemoteHost(const std::string host, const std::string port);
        void disconnectFromRemoteHost();
        bool messagesWaitingInIncomingMsgQueue();
        SoftwareBusMsg getMsgFromIncomingMsgQueue();
        void addMsgToOutboundMsgQueue(SoftwareBusMsg& sbMsg);
        bool isConnected();

    private:
        void writeOutboundMsgToSocket();
        void deserializeHeader(std::string headerStr, MsgHeader& msgHdr);
        void addMessageToIncomingMsgQueue(SoftwareBusMsg& sbMsg);
        void readIncomingMsgHeader(MsgHeader& msgHdr);
        std::string readIncomingMsgData(uint32_t msgDataLength);
        SoftwareBusMsg readMsgFromSocket();
        void incomingMsgThread();
        void outboundMsgThread();
        void startReadAndWriteThreads();

        boost::asio::io_service io_srv;
        boost::asio::ip::tcp::socket tcpSocket;
        std::string remoteHost;
        std::string remotePort;
        bool connectedToRemoteHost;

        std::deque<std::string> outboundMsgQueue;
        std::mutex outboundMsgQueueMutex;
        boost::interprocess::interprocess_semaphore messagesInOutboundMsgQueue;

        std::deque<SoftwareBusMsg> incomingMsgQueue;
        std::mutex incomingMsgQueueMutex;
        //boost::interprocess::interprocess_semaphore messagesInIncomingMsgQueue;

};
#endif

I want the other classes, such as those responsible for motor control, to have the capability to send messages to the server for telemetry/error reporting. I may be wrong here, but it seems like it would be poor design to directly pass an instance of the TcpCom class to each class that needs the ability to send messages to the server.

Instead, I tried creating a EventReporter class that has a private member that is a reference to the TcpCom class. This would allow the encapsulation of code for handling different types of events (info, errors) and I could pass an initialized 'EventReporter' object to everything that needs it.

#include "TcpCom.hpp"

class EventReporter
{
    public:
        EventReporter(TcpCom& tcpComIn) : tcpCom(tcpComIn)
        {}
        //Will contain call to tcpCom.addMsgToOutboundMsgQueue()
        void reportEvent(std::string eventType, std::string message);
    private:
        TcpCom tcpCom;
};

When I tried compiling this code I got a few errors:

error: use of deleted function 'TcpCom::TcpCom(const TcpCom&)'

error: use of deleted function 'boost::asio::io_service(const boost::asio::io_service&)'

It looks like my new class would be trying to make a copy of TcpCom , which I thought I was avoiding by passing it by reference.

Should I use something like a unique_ptr to avoid copying TcpCom , or is there a better way to make networking functions accessible from other classes?

Thanks!

Kind of tossed up whether to answer this or close as a typo, so I'll post and let the question's Asker tell me.

In

class EventReporter
{
    public:
        EventReporter(TcpCom& tcpComIn) : tcpCom(tcpComIn)
        {}
        //Will contain call to tcpCom.addMsgToOutboundMsgQueue()
        void reportEvent(std::string eventType, std::string message);
    private:
        TcpCom tcpCom; //<- this is not a reference
};

TcpCom tcpCom; defines an instance of TcpCom , not a reference to a TcpCom as the Asker stated they wanted, so tcpCom(tcpComIn) in the member initializer list (Good on them for using the list, by the way. Many C++ programmers who think they are no longer learning don't seem to know they exist) performs the copy They are trying to avoid by passing by reference in the parameter list.

The error messages result from members (std::mutex at the very least. Multiple copies of a mutex would be bad) of TcpCom being uncopyable, so you can't copy one even if you want to.

The simple solution is

class EventReporter
{
    public:
        EventReporter(TcpCom& tcpComIn) : tcpCom(tcpComIn)
        {}
        //Will contain call to tcpCom.addMsgToOutboundMsgQueue()
        void reportEvent(std::string eventType, std::string message);
    private:
        TcpCom & tcpCom; //<- change made here
};

Unless the Asker has other uncopyable objects also being copied else where in their code or the the EventReporter instance can outlive the source TcpCom they should be good to go.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM