This looks slightly circuitous to me.
It is!
Is there a reason to have Sock::WaitMany be an instance method instead of a static one?
Yes. It is easier to override/mock it this way in tests.
It acts on multiple sockets at once, not one socket, after all, does it matter which one you call it on?
No it does not matter. Indeed it does not access any of the member variables and acts only on the sockets that are passed as arguments. As such it is more natural for it to be a standalone function or a static method of the Sock class.
I chose to have it as virtual method of the Sock class because this way it is easier for tests to provide a mocked alternative of it - just by providing a mocked Sock class, e.g. FuzzedSock.
If WaitMany() is a standalone function it would have to be done in a similar way like CreateSock() and g_dns_lookup() - global variables that point to “real” functions but are re-pointed to mocked functions in tests. So, each test that wants to mock those would have to override WaitMany() in addition to CreateSock(). Should I try to do it like that?