In C++, suppose I have a messaging system that wraps messages in a generic struct:
template<typename T>
struct Message
{
std::string Name;
T Data;
};
I also have an interface that includes functions that need to use the purely generic version of this struct:
class Interface
{
public:
virtual ~Interface() { }
virtual void Receive(Message& message) = 0;
virtual Message Send() = 0;
};
However, Message no longer names a type; things like Message<float> and Message<std::string> name types. Since the classes that will be implementing Interface will want to catch different Message, I can't just define a specific type.
The only way I can think to fix this is to rip out the template and using inheritance, but then I'd have littered throughout my code things like IntMessage and BoolMessage, which looks extraordinarily ugly. Any thoughts on how I can do this the way I want?
A simple approach is to split the Message type into a hierarchy:
struct MessageBase {
std::string Name;
};
template<typename T>
struct Message : MessageBase
{
T Data;
};
Then you can just pass MessageBase& through interfaces.
[The previous won't work. The function will be able to accept any MessageBase& object, but Receive seems to be about storing in the argument a message for which the type is unknown a compile time. Although if you don't mind dynamic allocations you could have a Message that holds the name and a pointer to a MessageBase and then different implementations of MessageImpl (the template above)]
Another common approach is to add all possible messages to an union and pass the union around.
Why don't you define your interface as a template?
template<typename T>
class Interface
{
public:
virtual ~Interface() { }
virtual void Receive(Message<T>& message) = 0;
virtual Message<T> Send() = 0;
};
Related
I would like to do something that probably is not possible in Cpp, but I could not find a post about this specifically.
I want to have a derived class specify the type of a void* parameter on a virtual function.
I have a base class called interface with a send function.
// pure virtual
class Interface{
virtual bool Send(const void*)=0;
};
struct Packet{
DataType data;
};
class SpecificInterface{
bool Send(const DataType*);
}
Is there a way to make something like this work? The intent is that SpecificInterface::Send implements Interface::Send. Allowing SpecificInterface to not be a pure virtual while restricting the void* to a specific packet type.
Otherwise I know I could take a void* parameter and static_cast it into the Packet* type; however, I do not want others to send a pointer type that cannot be cast to Packet*.
Let me know if this is not clear
When you want to override a virtual function, the number of arguments and the types of the arguments must exactly match the declaration in the base class. You'll have to use:
class SpecificInterface{
bool Send(const void* ptr)
{
cont DataType* dataTypePtr = static_cast<const DataType*>(ptr);
// Now use dataTypePtr any way you wish
}
};
Please note that use of such code is dangerous. If ptr does not really point to a DataType object, your program will have undefined behavior.
#RSahu is correct, of course. You could still use a virtual method to do about the same thing:
class Interface {
virtual bool send(const void*) = 0;
};
struct Packet {
DataType data;
};
class SpecificInterface {
bool send(cont void*) override {
send(static_cast<DataType*>(data));
}
bool send(cont DataType*); // code which actually does something
};
However - I recommend against your whole approach to begin with - it is massively unsafe, since the validity of the type is never checked! It's a source of many potential bugs. More often than not, you can avoid doing this. Here are a few things you might try instead:
std::any - a class which doesn't offer you compile-time type safety, but at least checks types at run-time. You would have a send(const std::any& data) virtual function, and inside it you would call std::any_cast<DataType>(data) to get a DataType or std::any_cast<DataType>(&data) to get a DataType *.
Probably even better - the Curiously-recurring template pattern (CRTP):
template <typename T>
class Interface {
virtual bool send(T*) = 0;
};
class SpecificInterface : Interface<DataType> {
bool send(cont DataType*) override;
}
I am implementing a variation of the observer pattern in C++. However, because of the nature of the nature of my project, it CANNOT USE ANY VIRTUAL MEMBER FUNCTIONS, as the aggregate overhead from vtable lookups and cache misses is unacceptable.
Were I to create interfaces via virtual member functions, I would trivially write the following:
template <class MessageType>
class MessageSubscriber {
public:
virtual void OnMessage(MessageType *message) = 0;
};
template <class MessageType>
class MessagePublisher {
public:
void AddSubscriber(MessageSubscriber<MessageType> *subscriber) {
subscribers.push_back(subscriber);
}
protected:
void Publish(MessageType *message) {
for (auto subscriber : subscribers)
subscriber.OnMessage(message);
}
private:
std::vector<MessageSubscriber<MessageType>*> subscribers;
};
Then, for example, I could have classes that implement MessageSubscriber for some MessageType, SafetyMessage, like so:
class SafetyMessageSubscriberA : public MessageSubscriber<SafetyMessage> {
public:
virtual void OnMessage(SafetyMessage *message) override {
/* process message */
}
};
class SafetyMessageSubscriberB : public MessageSubscriber<SafetyMessage> {
public:
virtual void OnMessage(SafetyMessage *message) override {
/* process message */
}
};
class SafetyMessagePublisher : public MessagePublisher<SafetyMessage> {
public:
void Run {
/* manipulate message data */
this->Publish(&message);
}
private:
SafetyMessage message;
};
This would get the job done, but, as emphasized earlier, the vtable lookup overhead is unacceptable in the context of the application despite the polymorphic convenience that it provides and is also needed for the application. Naturally, then, I tried several approaches centering around the static polymorphism that can be leveraged through templates.
I first tried to utilize CTRP, but it fails in this case because the pointers contained in MessagePublisher::subscribers must point to the same base class when MessagePublisher::Publish(MessageType *message) is called. Ergo, you could not have some CTRP pattern along the lines of MessageSubscriber<SafetyMessageSubscriberA>, MessageSubscriber<SafetyMessageSubscriberB>, as the template arguments would need to be the same for both objects to legally be allowed in MessagePublisher::subscribers.
My most recent attempt at the problem has lead me to try some variations of member function template specialization, albeit unsuccessfully. I have tried the following variation on the pattern interface:
class MessageSubscriber {
public:
template <class MessageType>
void OnMessage(MessageType *message);
};
class MessagePublisher {
public:
template <class MessageType>
void Publish(MessageType *message) {
for (auto subscriber: subscribers)
subscriber->OnMessage<MessageType>(message);
}
private:
std::vector<MessageSubscriber*> subscribers;
};
template<class MessageType>
void MessageSubscriber::OnMessageOnMessage(MessageType *message) {
/* "interface" call; do nothing */
}
With implementations such as:
class SafetyMessageSubscriberA : public MessageSubscriber {
public:
// declare for legal overload
template <class MessageType>
void OnMessage(MessageType *message);
};
class SafetyMessageSubscriberB : public MessageSubscriber {
public:
// declare for legal overload
template <class MessageType>
void OnMessage(MessageType *message);
};
template<>
void SafetyMessageSubscriberA::OnMessage<SafetyMessage*>OnMessage(SafetyMessage *message) {
/* process message */
}
template<>
void SafetyMessageSubscriberB::OnMessage<SafetyMessage*>OnMessage(SafetyMessage *message) {
/* process message */
}
When I tried this, however, MessagePublisher::Publish(SafetyMessage *message) would always call the generic MessageSubscriber::OnMessage(MessageType *m)implementation for the base class, not the ones that were implemented for the derived classes specific to SafetyMessage*.
Am I incorrectly specializing the function templates as intended, or is there another more efficient solution? I apologize in advance for any imprecise wording as it relates to the concepts of overloading and member template specialization.
You can cut out one level of indirection by using C-style function pointers in place of virtual functions. Thus, in the declaration of your base class you might have something like:
void (*) OnMessage (BaseClass *self, MessageType *message);
You then initialise this instance variable in each of your derived classes' constructors to point to the appropriate static member function, which in turn allows you to call it via a single indirect call (as opposed to two if you went via the vtable).
Finally, sadly, you will need to cast self in each of the target functions in the derived classes, which is the price you pay for all this trickery. Either that or cast the function signature when assigning the function pointer. I will post a fuller example if interested - let me know.
I am creating a simple event system where multiple listeners can be notified on a specific topic and when an event is fired, it can pass a generic payload to the event, and the listeners will match the format of the fired event. However, because it's not possible to use templates on a virtual function, how else can I achieve this?
class AEventListener
{
public:
template<class T>
struct PayloadObject {
T obj;
};
explicit AEventListener();
virtual ~AEventListener();
//error here because T is undefined. Each PayloadObject may have a different type
virtual void notify(vector<shared_ptr<PayloadObject<T>>> payload) = 0;
};
The notify method is called when an event topic has a listener subscribed, but I want a generic way of just passing a load of random objects to the listener.
For example
fireEvent("test.topic", Payload { 0, "hello", 123 });
//...
listener.notify(payload);
How would I go about this in C++?
I have managed to get around this, although I don't think this is the best way and could slow down performance.
template<class T>
struct PayloadObject : public APayloadObject {
T obj;
PayloadObject(T obj) {
this->obj = obj;
}
~PayloadObject() override {
};
};
struct APayloadObject {
virtual ~APayloadObject();
};
Firing:
vector<shared_ptr<APayloadObject>> payload;
payload.push_back(shared_ptr<PayloadObject<int>>(new PayloadObject<int>(5))); //payload[0] = int - 5
Events::fire(EventKeys::DISCONNECTION_EVENT, payload);
Notifying:
shared_ptr<PayloadObject<int>> number = dynamic_pointer_cast<PayloadObject<int>>(payload[0]);
int id = number.get()->obj; //payload[0] = int - 5
One simple approach is to come up with a common base or common interface for the Payload objects. So that they are not a template class.
struct Payload {
virtual ~Payload() = default;
virtual std::string foo() const;
virtual std::string bar() const;
};
Another way is to use a variant type for the payload objects:
using Message_t = boost::variant<A, B, C>;
and then make AEventListener take the Message_t type so that it doesn't require the member function to be a template.
class AEventListener
{
public:
virtual ~AEventListener();
virtual void notify(std::vector<Message_t> payload) = 0;
};
In C++17 you could use std::variant for this instead of boost.
Yet another way is to skip using a variant, and just make it so that the Listener must implement three different functions, one for each type:
class AEventListener
{
public:
virtual ~AEventListener();
virtual void notifyA(A payload) = 0;
virtual void notifyB(B payload) = 0;
virtual void notifyC(C payload) = 0;
};
More generally, it is pretty difficult in C++ to make a concept like "Function object that is callable with any particular type of arguments". This is in part because... it is not very useful, there is not much that you can do generically with data of ANY type that you can assume nothing about.
So I would suggest that you think hard about refining your Event Listener concept, and make more concrete what it is that objects of this type are ACTUALLY supposed to be required to do.
What is the most elegant way to provide an interface in C++ that accepts derived class types that carry with them different data type members that then need to be retrieved later. The example below illustrates this where the Container class provides methods to "post" an Item that will be some kind of derived variant of BaseItem. Later on I want to get the derived Item back and extract its value.
The main thing I want is for the Container interface (post and receive) to stay the same in the future while allowing different "Item" derived types to be defined and "passed" through it. Would template be better for this somehow; I'd rather not use RTTI. Maybe there is some simple, elegant answer to this, but right now I'm struggling to think of it.
class ItemBase {
// common methods
};
class ItemInt : public ItemBase
{
private:
int dat;
public:
int get() { return dat; }
};
class ItemDouble : public ItemBase
{
private:
double dat;
public:
double get() { return dat; }
};
class Container {
public:
void post(int postHandle, ItemBase *e);
ItemBase* receive(int handle); // Returns the associated Item
};
int main()
{
ItemInt *ii = new IntItem(5);
Container c;
c.post(1, ii);
ItemInt *jj = c.receive(1);
int val = jj->get(); // want the value 5 out of the IntItem
}
This is definitely a candidate for generic programming, rather than inheritance. Remember, generics (templates) are ideal when you want identical handling for different data types. Your ItemInt and ItemDouble classes violate OO design principles (the get() method returns different data types depending on what the actual subtype is). Generic programming is built for that. The only other answer would be a tagged data type, and I personally avoid those like the plague.
How about?
template<typename T>
class Item
{
private:
T dat;
public:
T get() { return dat; }
};
class Container {
public:
template<typename T>
void post(int postHandle, Item<T> *e);
template<typename T>
Item<T>* receive(int handle); // Returns the associated Item
};
int main()
{
Item<int> *ii = new Item<int>(5);
Container c;
c.post(1, ii);
Item<int> *jj = c.receive<int>(1);
int val = jj->get(); // want the value 5 out of the IntItem
}
Your Container class looks suspiciously like a std::map. It looks to me like your ItemBase class is just a different name for "Object", the universal base class, which I think is not much different from (or better than) void*. I would avoid trying to contain items of different type in a single container. If your design seems to call for doing so, I'd rethink your design.
A pure template approach doesn't work because you apparently want to have mixed types in your container. You could work with something like Boost's any although I think you need to restore the actual. What I think is called for in this case is a base class exposing the type-independent and virtual methods plus a templatized derived class to hold the actual items:
class Base {
public:
virtual ~Base() {}
virtual void post() = 0;
};
template <typename T>
class Item: public Base {
public:
Item(T const& value): value_(value) {}
void post() { std::cout << "posting " << this->value_ << "\n"; }
private:
T value_;
};
This approach avoids the need to write any derived Item class for another value type. To make creation of these beast easier you probably want to create a suitable creation function as well, e.g.
template <typename T>
std::unique_ptr<Base> make_item(T const& value) {
return std::unique_ptr<Base>(new Item<T>(value));
}
A std::unique_ptr<Base> is returned to make sure that the allocated object is released (if you don't use C++2011 you can used std::auto_ptr<T> instead). This type can easily be converted to other pointer types, e.g. to a std::shared_ptr<Base> which is a better suited to be put into a container.
I have a base class which implements the following:
struct Consumer
{
template <typename T>
void callback(T msg) { /*null implementation */ }
};
I then have a class implement this:
struct Client : public Consumer
{
void callback(Msg1 msg);
void callback(Msg2 msg);
void callback(Msg3 msg);
};
The issue is I have a container of Client objects treated as Consumer* and I can't think of a way to get these Consumer objects to call the derived functions. My intended functionality is to have multiple Clients each of which implement an overloaded function for each Msg class that means something to them and the rest of the calls simply call the null implementation in the base class
Any thoughts how I can get the derived class to be called? Right now I need to implement every overloaded function in Consumer and mark them as virtual.
Cheers,
Graeme
If you really don't want to use virtual functions (this seems to be a perfect use case for them actually, but I don't know about your message classes), you can use the CRTP:
template <typename U>
struct Consumer
{
template <typename T>
void callback(T msg)
{ static_cast<U*>(this)->callback(msg); }
};
struct Client : Consumer<Client>
{
void callback(Msg1 msg);
void callback(Msg2 msg);
void callback(Msg3 msg);
};
The problem, of course, is that you cannot store Consumer objects in a container any more. Since everything is compile time, the actual type of the client must be stored alongside the consumer object for the compiler to call the right callback function. Virtual functions allow you to wait until runtime for this...
Is there a reason not to have Msg classes polymorphic and use standard virtual functions (other than "I have to rewrite all the code and I cannot") ?
EDIT If your concern is about message classes, why not use something like that, assuming message classes implement a DoSomething member function: (this technique is known as Type Erasure)
struct AnyMsg
{
template <typename Msg>
AnyMsg(Msg x) : impl(newImpl(x)) {}
void DoSomething() { impl->DoSomething(); }
private:
struct Impl
{
virtual ~Impl() {}
virtual void DoSomething() = 0;
};
// Probably better is std::unique_ptr if you have
// C++0x. Or `boost::scoped_ptr`, but you have to
// provide copy constructors yourself.
boost::shared_ptr<Impl> impl;
template <typename Msg>
Impl* newImpl(Msg m)
{
class C : public Impl
{
void DoSomething() { x.DoSomething(); }
Msg x;
public:
C(Msg x) : x(x) {}
};
return new C(m);
}
};
You can customize the behavior of newImpl to get what you want (eg. default actions if there is no DoSomething member function in the message class, specialization for some message classes or anything else). This way, you implement Msg classes like you would have done with your template solution, and you have a unique facade that you can pass to the virtual functions in your client classes.
If the Message classes are going to be very different, and client classes may react differently to them, and you are going to have a lot of message classes, this begins to smell. Or perhaps you have a candidate for the ugly and scary Visitor pattern.
Since you don't want to use virtual methods, the compiler would have to know statically (i.e. at compile time) which function to call. If you have different client objects in your container, there is now way the compiler could possibly know this. So I think there's no solution to your problem without using virtual methods (which are btw. exactly designed for this kind of situations...).
Of course you could alternatively using some switch statements for manually deriving the concrete type, but this is neither elegant nor efficient (and you would have to hardcode all possible client types ...)
EDIT
Personally, I'd implement some base message class containing a type code and implement a switch statement in the client class to handle different message types like:
struct MsgBase {
int type;
};
struct Consumer {
virtual void callback(MsgBase msg) { };
};
struct Client : public Consumer {
void callback(MsgBase msg) {
switch (msg.type) {
case MSGTYPE1:
callback((Msg1)msg);
break;
case MSGTYPE2:
callback((Msg2)msg);
break;
// ...
}
}
void callback(Msg1 msg) { /* ... */ }
void callback(Msg2 msg) { /* ... */ }
};
You could also make MsgBase polymorphic (e.g. virtual destructor) and use typeid to differentiate (more elegant but slightly less efficient ...)
struct Client : public Consumer {
void callback(MsgBase* msg) {
if (typeid(*msg) == typeof(Msg1))
callback(static_cast<Msg1*>(msg));
else if (typeid(*msg) == typeof(Msg2))
callback(static_cast<Msg2*>(msg));
}
// ...
};
This is always a difficult situation to make totally extensible, as is the case usually with the Visitor pattern.
You end up needing up to V*T implementations where V is the number of "visitors" and T is the number of types being visited and will probably end up having to use a mixture of visitor and class factory pattern.
visitors here would be your consumers
class factory would be used for the message types.
and your best way to make it totally extensible is to create new function "objects" for message/consumer pairs and a bit of double-dispatch to ensure the right one gets called.
In your case you have different messages come in and then you give them to your consumers who might handle them? So each message should have an identifiable "type" and your consumer
should look up this type in a table to create a handler for it.
You can have one handler per type per consumer class.