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();
Related
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.
I have many, many modules that can benefit from using the exact same design pattern and share common classes. On the individual component level, everything makes sense, classes can easily be extended. But when I try to tie them together into a common module object, it seems like a pattern that polymorphism wasn't meant for, and I am missing the right pattern or design.
Starting out with all the base classes, which all other classes will extend from. The Module is the glue and the problem. Module will contain methods that prevent code duplication, such as AddComponent.
// A physical interface (Ethernet, Bluetooth, etc)
class Interface {};
// A basic component
class Component {};
// An std::map wrapper for managing Components
class ComponentManager {};
// A place to store data
class Database {};
// A module to tie all things together
class Module {
public:
Interface interface;
ComponentManager manager;
Database db;
void AddComponent(Component& c) {
manager.AddComponent(c);
db.InsertComponent(c);
}
};
Everything is fine until we want to extend all or most of the classes and the Module as well.
class EthInterface : public Interface {}; // cool
class UdpClientComponent : public Component {}; // cool
class UdpClientDatabase : public Database {}; // cool
//class UdpClientComponentManager : public ComponentManager {}; // 90% of the time won't need it
class UdpClientModule : public Module {
public:
EthInterface interface; // how to get an EthInterface instead of Interface?
UdpClientDatabase db; // how to get a UdpClientDatabase instead of Database?
};
I am trying to understand what pattern or design or what to use here. I think templates might not be the right solution because I've simplified this example, and don't think templates with 5 or 6 Ts are good design. I don't really get how to design this using ptrs because then I am feeding the extended Module ptrs from the outside, and I want this to be self contained, so that people can just write UdpClientModule module and they get batteries included, so to speak.
This might be a kick in the dark, but maybe it will send you searching in a different direction... You could use templates, redefining Module to look something like this:
template <class IFC, class COMP, class CM, class DB> class Module {
public:
IFC interface;
CM manager;
DB db;
void AddComponent(COMP& c) {
manager.AddComponent(c);
db.InsertComponent(c);
}
};
But if you go that way you should make sure that IFC, COMP, CM and DB are derived from Interface, Component, ComponentManager and Database and for that you need concepts. I don't know about you, but that is a bit over my head, so I would go a different way:
class Module {
public:
Module(Interface &ifc, Database &_db) :
interface(ifc),
manager(), db(_db) {
}
void AddComponent(Component& c) {
manager.AddComponent(c);
db.InsertComponent(c);
}
private:
Interface &interface;
ComponentManager manager;
Database &db;
};
class UdpClientModule : public Module {
public:
UdpClientModule() :
Module(ethInterface, udpClientDb),
ethInterface(),
udpClientDb() {
}
private:
EthInterface ethInterface;
UdpClientDatabase udpClientdb;
};
It's still clumsy, but it at least gets you some of the way to where (I assume) you want to get.
Interfaces depends from abstraction, you want to depend from concrete types and there where your design flaw. Keep the interface to do the "interface" and leave the concrete classes dealing with the concrete types.
class Module {
public:
virtual ~Module() = default;
void AddComponent(Component& c) {
manager().AddComponent(c);
db().InsertComponent(c);
}
virtual Interface& interface() = 0;
virtual ComponentManager& manager() = 0;
virtual Database& db() = 0;
};
class UdpClientModule : public Module {
public:
Interface& interface() override { return ethInterface; }
ComponentManager& manager() override { return udcClienddb; }
Database& db() override { return manager; }
void specialUdpMethod() const { /*...*/}
private:
EthInterface ethInterface;
UdpClientDatabase udpClientdb;
ComponentManager manager;
};
In this case you're stating every module must provide an interface, e component manager and a db. If you have more relaxed constraint you could move the dependencies to a dependency injection solution and use pointer instead.
Is there a way to do the following with templates? The following code throws unknown type compile time errors.
I'm trying to create two different types of Application, those that inherit from Application, and those that inherit from Service, which inherits from Application. All Applications have one service called Cron, which will inherit from Service. Applications will be threaded and detached, while Services that derive from Application will be threaded and joined. I broke this down to simplest terms.
#include <iostream>
class Application
{
public:
Service service; //Throws unknown type... Forward decl. will not work either.
};
class Service:public Application
{
};
int main(int argc, const char * argv[])
{
// insert code here...
std::cout << "Hello, World!\n";
return 0;
}
Thanks,
Bruce
No, there is no way to do what you want, because what you want to do is nonsense. Hold on, I'll explain.
Service is derived from Application, but Application has a member of type Service.
This is a cyclic dependancy but beyond that, I just don't understand it. Since Service is derived from Application, which has a member of type Service, which is derived from Application, which has a member of type Service... you get the idea. It's like standing in front of a mirror with a mirror and trying to find the end.
Now the question becomes, what are you really trying to do?
In your comments, you said:
I'm trying to create two different types of Application, those that
inherit from Application, and those that inherit from Service, which
inherits from Application. All Applications have one service called
Cron, which will inherit from Service.
There's still a little ambiguity here. How can Application derive from Application?
I suspect that what you're after is having two different concrete instantiations of the class which implements Service. One only implements Service, and the other implements other stuff too.
In that case:
class Service
{
public:
void Cron();
};
class Application
{
public:
void OtherStuff();
};
But you also said:
Applications will be threaded and detached, while Services that derive
from Application will be threaded and joined.
That sounds like a job for a policy-based design.
class DetatchedPolicy
{
public:
void StartThread(); // this function would start the thread and detatch
};
class JoinedPolicy
{
public:
void StartThread(); // this function would start the thread and join
};
template <typename ThreadingPolicy>
class BasicService
:
public ThreadingPolicy
{
public:
Service()
{
StartThread();
}
void Cron();
};
typedef BasicService <JoinedPolicy> Service;
typedef BasicService <DetatchedPolicy> Application;
I think what you actually want to do is to use a pointer.
class Service;
class Application
{
std::shared_ptr<Service> m_service;
};
class Service : public Application
{
};
It sounds to me like you may benefit from separating the interfaces from the implementations:
struct ApplicationInterface
{
virtual ~ApplicationInterface() {}
virtual void do_application_stuff_1() = 0;
virtual void do_application_stuff_2() = 0;
};
struct ServiceInterface
: public ApplicationInterface
{
virtual ~ServiceInterface() {}
virtual void do_service_stuff_1() = 0;
virtual void do_service_stuff_2() = 0;
};
class CronService
: ServiceInterface
{
public:
// ApplicationInterface
virtual void do_application_stuff_1() {}
virtual void do_application_stuff_2() {}
// ServiceInterface
virtual void do_service_stuff_1() {}
virtual void do_service_stuff_2() {}
};
class Application
: ApplicationInterface
{
protected:
CronService cron;
public:
virtual void do_application_stuff_1() {}
virtual void do_application_stuff_2() {}
};
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;
};
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> {
};