Wrapping Winsock functions in C++ classes

点点圈 提交于 2020-02-29 05:25:28

问题


I've seen some people creating a "is-a" relationship like the following:

class TCPClient : public Socket
{
public:
    TCPClient(const std::string& host, unsigned short port);
};

where the Socket class implements Winsock functions such as Connect(), Close(), Bind() etc.

Examples:

  • Example 1
  • Example 2

But this doesn't feel natural to me who is a newbie in socket programming.

Does the above hierarchy make more logical sense than the following "has-a" counterpart?

class TCPClient
{
public:
    TCPClient(const std::string& host, unsigned short port);
    ....
private:
    Socket m_socket;
};

回答1:


A TCPClient uses a socket or has a socket, but is not itself a socket, and you wouldn't normally expect to be able to substitute a TCPClient anywhere a socket was expected. As such, public inheritance doesn't make sense.

You could use private inheritance for this case, but (at least in a typical case) it probably doesn't make much sense either. Private inheritance makes sense primarily when the base class provides at least one virtual function you plan to override in the child class. If you have a virtual function and need to override it, you have no real choice but to use inheritance. I wouldn't expect a Socket class to have an virtual functions though; that wouldn't normally apply here.

That basically leads to your second solution: the TCPClient should contain an instance of a Socket, rather than using inheritance at all.

I should add, however, that the Socket class you've shown seems to conflate the notion of an actual socket with the notion of an address. My first socket class (years ago) worked about like that, but since then I've concluded that it's not really an ideal design. I've become convinced that it's worthwhile to keep the notion of an address separate from the socket itself. Though mine is a bit less elaborate, I find it interesting that what I came up with looks almost like it could have been the prototype from which Boost ASIO was derived. It's a little smaller and simpler, but a lot of the basic ideas are generally pretty similar anyway.

That leads to my next recommendation: take a look at Boost ASIO. Lacking a fairly specific reason to do otherwise, it's what I'd advise (and generally use) in most new code. Although (as I said above) I've written several socket classes over the years, I haven't used any of them in much (any?) new code in quite a while now -- they really only have two possible advantages over ASIO. The first applies only to me: since I wrote and used them before ASIO existed, I already understand them and how they work. The second may be similar: at least to me, they seem a little bit smaller and simpler (but, again, that may be just because I used them first). Even so, the advantages of (for example) using something other people already understand trumps those quite easily.




回答2:


Use has-a. A TCPClient uses a socket like a person uses a telephone. Would you derive a Person from a Telephone?




回答3:


class TCPClient : public Socket
{
public:
    TCPClient(const std::string& host, unsigned short port);
};

Network sockets are used not only in TCP/IP and the above design is more suitable if you plan to reuse your "Socket" class to implement other protocols using network sockets. For example:

class UDPClient : public Socket
{
};



回答4:


I would say so. Socket is an abstraction, a file descriptor (UNIX) or handle (Windows), which has resources associated with it and is managed by the operating system. If we consider OSI model, the socket fits well into the presentation layer (it presents, or describes, a communication channel between two nodes), whereas a program that uses the socket sits on the application layer.

Considering this, I would prefer not to inherit from the socket, unless I implement a kind of advanced socket (by analogy: C-pointer vs. smart pointer) to present and handle a logical connection and somehow manage the resources associated with the socket. If XYZClient is an application, whose goal is to implement some business or data processing logic, I would not mix these two concepts together and use the second approach (has-a).

I would split infrastructure/resource-specific and business/application-specific logic.



来源:https://stackoverflow.com/questions/11282656/wrapping-winsock-functions-in-c-classes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!