C++ Templates and Inheritance - c++

Let's say I have a simple Server with a template which accepts a Client as it's template argument:
template<class T>
class Server<T>{
Server(int port);
}
and a Client is defined something like this:
class Client{
Client(Server<Client> *server, // <--
int socket);
};
But I also want say, have the class User inherit from Client (class User : public Client), so I could do Server<User> instead of Server<Client>. class User obviously needs to pass Server<Client> as a parameter when constructing Client. However, with the current implementation this seems impossible.
How should I approach this problem?

What about this?
template<class T>
class Server<T>{
Server(int port);
};
template<class Derived>
class Client {
Client(Server<Derived> *server, int socket);
virtual ~Client() {} // Base classes should have this
};
class User : public Client<User> {
};

Related

C++ Abstraction OOP (Inherit only some method to derived class)

Suppose i have a socket class:
class Socket{
public:
... Some Code ...
Socket(int type){
isServer = type;
//some code
}
virtual void Send(string s);
virtual void Send(string s, int clientID);
... Some Code ...
private:
int isServer;
};
This is to be used both as a server and client.
Now I need to have 2 Derived classes:
class ClientSocket : public Socket{
public:
... Some Code ...
};
class ServerSocket : public Socket{
public:
... Some Code ...
};
What I want is that ClientSocket will only have access to Send(string) and server socket will only have access to Send(string, int)
I checked some other answer:
https://stackoverflow.com/a/20997981/14911094
And that has a good idea of not using inheritance at all rather just encapsulate(Have a socket instance in server). But I want to know whether this can be done using Inheritance.
There is not absoulte way to doing such thing.
But here my idea:
create two class(like interface):
first class is server socket sender:
Class ServerSocketSender {
public:
virtual void Send(string s, int clientID);
}
second class is client socket sender:
Class ClientSocketSender {
public:
virtual void Send(string s);
}
due to interface segregation principle i recommend you to do such thing it is not wise choice to combine two send method in one class and enable desire method in desire class.
another trick that i saw many times but i dont know exactly if it's work in your case or not is something called SFINAE. with this trick i think you can achieve same thing but due to complexity i not recommend this approach.

Using template type to generate unique member names for that template type

This use case comes from wanting to implement a compile-time event bus data structure that only listens/registers/unregisters specifically for the provided template arguments.
Starting with a naive implemention lets say we have the following classes AListener, AEvent, BListener, BEvent.
I want my EventBus class to look like this:
class EventBus {
std::vector<AListener*> aListeners;
std::vector<BListener*> bListeners;
public:
void registerListener(AListener& listener);
void unregisterListener(AListener& listener);
void sendEvent(AEvent event);
void registerListener(BListener& listener);
void unregisterListener(BListener& listener);
void sendEvent(BEvent event);
};
Is there a way I can template it and recursively construct the class? For example:
EventBus<AListener, AEvent, BListener, BEvent> eventBus;
AListener aListener;
eventBus.registerListener(aListener);
AEvent aEvent;
eventBus.sendEvent(aEvent);
BListener bListener;
eventBus.registerListener(bListener);
BEvent bEvent;
eventBus.sendEvent(bEvent);
Preferably it'd be nice to make a new vector for each listener type because it would be inefficient to put all the pointers in one list since a long list of irrelevant listeners would be a waste of performance. Since the event bus is going to have a lot of events going through it, performance is important. Iterating over only the ones we care about is desired.
Finally, assume that we will not specialize any listener so we don't have to worry about inheritance here, all classes in the template list are considered to be final.
My problem:
How do I get around naming? While I assume specializing templates in the recursive definition via method overloading is okay because the compiler will hopefully do the ideal thing... I'm not sure how to handle the different member names.
My plan was to take the list and pull off two members, sort of like this (NOTE this is pseudo-code and almost certainly does not compile, or if it does it is by pure chance):
// Pseudocodey C++ template rough idea
template <typename Listener, typename Event, typename Args...>
class EventBus : public EventBus<Args...> {
// ???
public:
void registerListener(Listener& listener) {
// emplace back
}
void unregisterListener(Listener& listener) {
// erase remove
}
void sendEvent(Event event) {
// send for each
}
};
Of course unless there is a better way? Is this possible?
I would create a class to handle Listener/event:
template <typename Listener, Event>
class EventHandler {
std::vector<Listener*> mListeners;
public:
void registerListener(Listener& listener);
void unregisterListener(Listener& listener);
void sendEvent(Event event);
};
Then, your class which handles all would be:
template <typename ... Ts>
class EventBus : Ts...
{
public:
using Ts::registerListener...; // Requires C++17
using Ts::unregisterListener...; // Prior that you have to do it with recursion
using Ts::sendEvent...; // class EventBus<T, Rest...> : T, EventBus<Rest...>
};
With usage:
EventBus<EventHandler<AListener, AEvent>, EventHandler<BListener, BEvent>> eventBus;
Btw, Event is probably dependent of Listener, so having typename Listener::Event seems appropriate and remove all Event template parameters.
You can use a tuple and some type traits:
#include <iostream>
#include <vector>
#include <tuple>
#include <utility>
template<typename x_Event> class
t_EventTrait;
template<typename ... x_Listener> class
t_EventBus
{
private: ::std::tuple<::std::vector<x_Listener *>...> m_listeners;
public: template<typename xx_Listener> void
Register_Listener(xx_Listener & listener)
{
::std::get<::std::vector<xx_Listener *>>(m_listeners).emplace_back(&listener);
}
public: template<typename x_Event> void
Send_Event(x_Event & event)
{
for(auto p_listener: ::std::get<::std::vector<typename t_EventTrait<x_Event>::t_Listener *>>(m_listeners))
{
p_listener->On_Event(event);
}
}
};
struct t_EventA {};
struct t_ListenerA { void On_Event(t_EventA &) { ::std::cout << "handling A\n"; } };
template<> class t_EventTrait<t_EventA>{ public: using t_Listener = t_ListenerA; };
struct t_EventB {};
struct t_ListenerB { void On_Event(t_EventB &) { ::std::cout << "handling B\n"; } };
template<> class t_EventTrait<t_EventB>{ public: using t_Listener = t_ListenerB; };
int main()
{
t_EventBus<t_ListenerA, t_ListenerB> bus{};
t_ListenerA a{};
bus.Register_Listener(a);
t_EventA ea{};
bus.Send_Event(ea);
t_ListenerB b{};
bus.Register_Listener(b);
t_EventB eb{};
bus.Send_Event(eb);
return 0;
}
online compiler
In C++11, you can use a variadic template
template<class... MoreEventPairs> class EventBus {};
template<class Listener, class Event>
class EventBus<Listener, Event>
{
private:
std::vector<Listener *> Listeners;
public:
EventBus() {};
~EventBus() {};
void registerListener(Listener& listener) {}; // dummy implementations here
void unregisterListener(Listener& listener) {};
void sendEvent(Event event) {};
};
template<class Listener, class Event, class ... MoreEventPairs>
class EventBus<Listener, Event, MoreEventPairs ...> : public EventBus<Listener, Event>,
public EventBus<MoreEventPairs ...>
{
public:
// these are needed so name resolution works
// one needed for each function, on both inheritance paths
using EventBus<Listener, Event>::registerListener;
using EventBus<Listener, Event>::unregisterListener;
using EventBus<Listener, Event>::sendEvent;
using EventBus<MoreEventPairs ...>::registerListener;
using EventBus<MoreEventPairs ...>::unregisterListener;
using EventBus<MoreEventPairs ...>::sendEvent;
};
// construct as
EventBus<ListenerA, EventA, ListenerB, EventB> bus;
This works by essentially peeling two types at a time from the parameter pack. It will not compile if you supply an odd number of types when constructing (e.g. leave off an Event type). You can specialise handling for a particular type of Listener or associated Event by using specialisation of the two-parameter template.
Before C++11, you could use multiple inheritance, but would need to construct the EventBus class separately. This is more effort to maintain, due to need to replicate code to extend.
template<class Listener, class Event> class ListenerBus
{
private:
std::vector<Listener *> Listeners;
public:
ListenerBus() {};
~ListenerBus() {};
void registerListener(Listener& listener) {}; // dummy implementations here
void unregisterListener(Listener& listener) {};
void sendEvent(Event event) {};
};
// AListener, AEvent, etc are concrete classes
class EventBus : public ListenerBus<AListener, AEvent>,
public ListenerBus<BListener, BEvent>
// list other types here
{
public:
using ListenerBus<AListener, AEvent>::registerListener;
using ListenerBus<AListener, AEvent>::unregisterListener;
using ListenerBus<AListener, AEvent>::sendEvent;
using ListenerBus<BListener, BEvent>::registerListener;
using ListenerBus<BListener, BEvent>::unregisterListener;
using ListenerBus<BListener, BEvent>::sendEvent;
// need to replicate above for every base class for name resolution
};
// construct as
EventBus bus;
The registerListener(), unregisterListener(), and sendEvent() member functions are all non-virtual since you don't want them to be over-ridden by EventBus (which will then be affected by the hiding rule).
In addition to assuming no inheritance relationships between any Listener or Event classes, both approaches above assume the Listener and Event classes are all distinct types (i.e. no Listener class or Event class listed more than once). The most likely outcome, if you break that assumption, will be that calls of some of the member functions will become ambiguous.

CRTP static polymorphism: is it possible to replace the base class with a mock?

I use CRTP static polymorphism in a websocket server to decouple networking code from business logic. The base class calls methods on the derived to process messages, the derived in turn calls the base to send/receive. It works like charm, looks something like this:
template<typename Derived>
class WebsocketSessionBase {
// basic websocket send/receive stuff
void someBaseMethod() {
static_cast<Derived*>(this)->otherDerivedMethod();
}
};
class WebsocketSession : public WebsocketSessionBase<WebsocketSession> {
// specific business logic
void someDerivedMethod() {
otherBaseMethod();
}
};
Now comes unit testing. Since the code is decoupled I would like the test functionality in the classes separately.
Testing the base class is simple:
class TestSession : public WebsocketSessionBase<TestSession> {
// same interface as WebsocketSession, but test code, cool!
};
But how do I test derived class? Adding a Base template parameter came to my mind, which makes test code ok (Base is a mock class). But I end up having 2 template classes referring to each other in the production version... :(
template<typename Base>
class TestableWebsocketSession : public Base {
};
using TestedWebsocketSession = TestableWebsocketSession<MockBase>;
using ProdWebSocketSession = TestableWebsocketSession<WebsocketSessionBase<... // infinite loop - now what!?
Is it possible to come over this?
I don't know if it's worth it, but you could make WebsocketSession a class template taking a template template parameter :
template<class T>
struct WebsocketSessionBase { /*...*/ };
template<template<class> class B>
struct WebsocketSessionDerived: B<WebsocketSessionDerived<B>>{ /*...*/ };
using WebsocketSession = WebsocketSessionDerived<WebsocketSessionBase>;
using DerivedTestSession = WebsocketSessionDerived<WebsocketSessionMockBase>;
struct BaseTestSession : WebsocketSessionBase<BaseTestSession>{ /*...*/ };

C++ Instantiate subclass from multiple choices

I'm using a library that implements different types of network protocols like in the following simplified example that hopefully illustrates the problem I have. NOTE: This is all pseudo code just to show the overall problem.
class Network
{
virtual void connect() {...}
void readPacket() = 0;
};
class NetworkClient : public Network
{
virtual void connect(int ip, int port) {super::connect() ...}
};
class NetworkServer : public Network
{
virtual void connect(int port) {super::connect() ...}
};
class ProtocolAClient : public NetworkClient
{
void readPacket() {...}
};
class ProtocolAServer : public NetworkServer
{
void readPacket() {...}
};
class ProtocolBClient : public NetworkClient
{
void readPacket() {...}
};
class ProtocolBServer : public NetworkServer
{
void readPacket() {...}
};
Now in my application, I want to have a Client and a Server, which should be either a ProtocolA or ProtocolB client/server, depending on which protocol the user chooses to connect with.
So I thought I could create my application classes like this.
class AppClient : public NetworkClient
{
... custom functionality needed by the app client ...
void sendAppData(...)
};
class AppServer : public NetworkServer
{
... custom functionality needed by the app server ...
void sendAppData(...)
};
Then I thought that when I need a client, for example, in the application I could just do this.
AppClient *client;
if(useProtocalA)
client = new ProtocolAClient;
else
client = new ProtocolBClient;
client->sendAppData();
However the compiler quickly let me know that this is not possible since ProtocolAClient and ProtocolBClient are not an AppClient. Here is the exact compiler error.
error C2440: '=' : cannot convert from 'ProtocolAClient *' to 'AppClient *'
So my next idea was to make AppClient and AppServer template classes, but that doesn't work either as you can't get a pointer to the instance as the pointer doesn't have a template argument like this.
AppClient *client; <--- Uh oh... missing template argument!
if(useProtocalA)
client = new AppClient<ProtocolAClient>;
else
client = new AppClient<ProtocolBClient>;
client->sendAppData();
This seems like it should be such a simple problem to solve, but I just can't seem to see the solution.
So you have the following classes:
class Network
{
virtual void connect() {...}
void readPacket() = 0;
}
class NetworkClient : public Network
{
virtual void connect(int ip, int port) {super::connect() ...}
}
class AppClient : public NetworkClient
{
... custom functionality needed by the app client ...
void sendAppData(...)
}
class ProtocolAClient : public NetworkClient
{
void readPacket() {...}
}
class ProtocolBClient : public NetworkClient
{
void readPacket() {...}
}
The problem is that you want an AppClient object, but the ProtocolAClient is of type NetworkClient and not type AppClient.
Your inheritance looks like this:
Network ---- NetworkClient ---- ProtocolAClient
|---- ProtocolBClient
|---- AppClient
As you can see, neither ProtocolAClient nor ProtocolBClient is of type AppClient, but all of them are of type NetworkClient.
So, if you want this code to work:
AppClient *client;
if(useProtocalA)
client = new ProtocolAClient;
else
client = new ProtocolBClient;
client->sendAppData();
you will have to do the one of the following changes:
A) change your ProtocolAClient and ProtocolBClient to inherit the AppClient class:
class ProtocolAClient : public AppClient
{
void readPacket() {...}
}
class ProtocolBClient : public AppClient
{
void readPacket() {...}
}
Now your inheritance looks like this:
Network ---- NetworkClient ---- AppClient ---- ProtocolAClient
|---- ProtocolBClient
or B) - Recommended: don't use AppClient as you already have NetworkClient:
NetworkClient*client;
if(useProtocalA)
client = new ProtocolAClient;
else
client = new ProtocolBClient;
client->sendAppData();
I think I'd stop right at:
class Network {};
class NetworkClient : public Network {};
class NetworkServer : public Network {};
At first glance, this already looks like a serious problem. Public inheritance implies the Liskov Substitution Principle--you should be able to substitute an instance of the derived class anywhere an instance of the base class is needed.
A NetworkClient (or a NetworkServer) is not a network, and I doubt there's even one circumstance in which either can be substituted for a network (not to mention all possible circumstances). As such, it seems to me that your basic design is problematic from the beginning.
My immediate reaction would be that you probably want something like:
class ProtocolA {};
class ProtocolB {};
template <class Protocol>
class Client {};
template <class Protocol>
class Server {};
With this, you can fairly easily instantiate a client or server using either protocol. This does not, however, support run-time substitution. That is to say, you don't get anything like a base class that lets you deal completely transparently (at runtime) with an object that may be any of two or more different types.
If you really need that, you probably want something more like:
class Protocol {};
class ProtocolA : public Protocol {};
class ProtocolB : public Protocol {};
class Client {
Protocol *p;
public:
Client(Protocol *p) : p(p) {}
};
class Server {
Protocol *p;
public:
Server(Protocol *p) : p(p) {}
};
[aside: despite following the syntax reasonably closely, this is really pseudo-code not C++. You clearly need to add a number of other things like virtual destructors before the code can actually be used at all.]
Then you instantiate an instance of the correct Protocol, and pass (a pointer to) that instance to create a Client or Server object.
With either of these, the Client/Server uses the Protocol to do communication, but (unlike with public inheritance) we have not made nonsensical assertions about being able to substitute a Client/Server for a network (or network protocol).
For me, your class hierarchy isn't precisely defined. In particular: what exactly is the NetworkClient class and what are you going to use it for? If this is to be used so that client->sendAppData() has to be called, then ProtocolAClient class should not derive from it. This solution you gave seems the best:
AppClient *client; <--- Uh oh... missing template argument!
if(useProtocalA)
client = new AppClient<ProtocolAClient>;
else
client = new AppClient<ProtocolBClient>;
client->sendAppData();
But you say you lack the ability to have this AppClient without specifying the protocol client class.
You can solve this problem by using virtual-template-pair idiom (or whatever name is used for it):
class AppClient { /* ... */ virtual void sendAppData() = 0; };
template <class ProtocolClientClass>
class AppClientSpec: public AppClient
{
/* ... */
ProtocolClientClass* inproto; // or whatever...
virtual void sendAppData() { return inproto->sendAppData(); }
};
And now your example can be fixed as:
AppClient *client; <--- Uh oh... missing template argument!
if(useProtocalA)
client = new AppClientSpec<ProtocolAClient>;
else
client = new AppClientSpec<ProtocolBClient>;
client->sendAppData();

C++ class template as property type

I have a class template in a c++ project:
template<class RequestHandler = DefaultRequestHandler>
class Server { ... }
I then have another class in which I want to hold an instance of Server<WhateverRequestHandlerIWant> as a property. So currently I have something like:
class OtherClass {
public: Server<>* server;
};
Unless I am mistaken, this will only allow me to store Server classes in which the template parameter is the class DefaultRequestHandler, correct?
Is there a way to write this without just making OtherClass a class template as well?
You could add a common abstract class for all server-like classes:
class IServer { ... };
then
template<class RequestHandler = DefaultRequestHandler>
class Server : virtual public IServer { ... }
and
class OtherClass {
public: IServer* server;
};