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.
Here's my issue, I'm trying to create a base class which can get a reference to a queue member in a derived class. I have two template functions in my base class :
class Base
{
template<TYPE type>
virtual void foo(std::queue<TYPE>*& typeQueue) //I know virtual isn't allowed
{
//do nothing as it's general case
}
template<typename TYPE>
void bar(TYPE type)
{
std::queue<TYPE>* typeQueue;
foo(typeQueue);
//... do some stuff with type
}
}
and a derived class which would theoretically be able to specialize the function foo for any types
class Derived : public Base
{
public:
template<>
void foo<int>(std::queue<int>*& m_integerQueue)
{
integerQueue= &m_integerQueue;
}
template<>
void foo<double>(std::queue<double>*& doubleQueue)
{
doubleQueue = &m_doubleQueue;
}
private:
std::queue<int> m_integerQueue;
std::queue<double> m_doubleQueue;
}
code above is more of about an ideology then a code to take word for word, I'd like the function bar to call the according function foo in derived class based on the type specified when bar is called. Of course this solution isn't working and the problem here is that we can't make template functions virtual.
I'm not sure if it's an error of design, but that's the general idea and I couldn't find an appropriate solution anywhere so I posted my own question here.
EDITED to make my problem clear
Supposing a general player that will notify certain events to certain objects of classes. I create a base class with some virtual functions guaranteed to exist in the derived:
class PlayEventsReceiver{
virtual void StartPlay()=0;
virtual void StopPlay()=0;
};
I would derive from PlayEventsReceiver the classes interested in such "signals"
class FooPlayer:public PlayEventsReceiver{
void StartPlay(){...}
void StopPlay(){...}
};
But if I wanted, rather than inheriting, implementing the signaling mechanism as a property, like this:
class BarPlayer{
PlayEventsReceiver receiver;
};
Is it possible to implement the pure virtual functions somehow inside the class BarPlayer in a clean way and not creating intermediate derived classes?
If you don't have a derived class then the compiler has nowhere to put its functions. If you are looking for something clean then creating an explicit derived class is probably as clean as it gets.
You can't escape the fact that somewhere you need to supply the function implementations.
However, it seems you can do this anonymously by creating an unnamed class/struct. But it is not avoiding creating a derived class because an anonymous derived class is still being created:
// public interface so I use struct
struct PlayEventsReceiver {
virtual void StartPlay() = 0;
virtual void StopPlay() = 0;
};
class BarPlayer {
public:
struct : PlayEventsReceiver {
void StartPlay() override
{
std::cout << "Start Play\n";
}
void StopPlay() override
{
std::cout << "Stop Play\n";
}
} receiver;
};
int main()
{
BarPlayer bp;
bp.receiver.StartPlay();
}
So i'm trying to better understand virtual methods.
I have a base class Sensor and several subclasses SensorTemp *SensorPh* SensorOrp
class Sensor
{
public:
virtual void updateValue();
}
the subclasses then override updateValue with their own method definitions (this happens in each of the subclasses)
.h file
#include "Sensor.h"
class SensorTemp : public Sensor
{
private:
public:
};
.Cpp file
#include "Sensor.h"
#include "SensorTemp.h"
void Sensor::updateValue(){
int reading = analogRead(pinId);
float voltage = reading * 5.0;
voltage /= 1024.0;
currentVal = voltage * 100 ;
Serial.print("temp: "); Serial.println(currentVal);
}
My issue is this works for the first subclass declaration, although the following will have a compiler error: updateValue() .... first defined here ld.exe : : Disabling relaxation: it will not work with multiple definitions
So I'm stuck on what type of approach I should take if I want to define the method differently from each subclass?
Any insight would be highly appreciated!
You subclass implementation should look like:
void SensorTemp::updateValue() {
// ...
}
It seems you are trying to learn dynamic dispatch through virtual keyword. In dynamic dispatch the actual type of object determines the appropriate method from that class to be called. To achieve this, the base class should provide a virtual method and each of the sub-classes should overrie that virtual method to provide their own behavior.
So each of your subclass should override the virtual method.
//.h file
class SensorTemp : public Sensor
{
private:
public:
virtual void updateValue();
};
//.cpp file
void SensorTemp::updateValue()
{
// ....
}
If your sub-classes do not override the virtual method then irrespective of the actual type of the object(be it base or sub-class) the Base class virtual method will be called.
I'm finding it difficult to describe this problem very concisely, so I've attached the code for a demonstration program.
The general idea is that we want a set of Derived classes that are forced to implement some abstract Foo() function from a Base class. Each of the derived Foo() calls must accept a different parameter as input, but all of the parameters should also be derived from a BaseInput class.
We see two possible solutions so far, neither we're very happy with:
Remove the Foo() function from the base class and reimplement it with the correct input types in each Derived class. This, however, removes the enforcement that it be implemented in the same manner in each derived class.
Do some kind of dynamic cast inside the receiving function to verify that the type received is correct. However, this does not prevent the programmer from making an error and passing the incorrect input data type. We would like the type to be passed to the Foo() function to be compile-time correct.
Is there some sort of pattern that could enforce this kind of behaviour? Is this whole idea breaking some sort of fundamental idea underlying OOP? We'd really like to hear your input on possible solutions outside of what we've come up with.
Thanks so much!
#include <iostream>
// these inputs will be sent to our Foo function below
class BaseInput {};
class Derived1Input : public BaseInput { public: int d1Custom; };
class Derived2Input : public BaseInput { public: float d2Custom; };
class Base
{
public:
virtual void Foo(BaseInput& i) = 0;
};
class Derived1 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived1Input& i) { std::cout << "Derived1 did something with Derived1Input..." << std::endl; }
};
class Derived2 : public Base
{
public:
// we don't know what type the input is -- do we have to try to cast to what we want
// and see if it works?
virtual void Foo(BaseInput& i) { std::cout << "I don't want to cast this..." << std::endl; }
// prefer something like this, but then it's not overriding the Base implementation
//virtual void Foo(Derived2Input& i) { std::cout << "Derived2 did something with Derived2Input..." << std::endl; }
};
int main()
{
Derived1 d1; Derived1Input d1i;
Derived2 d2; Derived2Input d2i;
// set up some dummy data
d1i.d1Custom = 1;
d2i.d2Custom = 1.f;
d1.Foo(d2i); // this compiles, but is a mistake! how can we avoid this?
// Derived1::Foo() should only accept Derived1Input, but then
// we can't declare Foo() in the Base class.
return 0;
}
Since your Derived class is-a Base class, it should never tighten the base contract preconditions: if it has to behave like a Base, it should accept BaseInput allright. This is known as the Liskov Substitution Principle.
Although you can do runtime checking of your argument, you can never achieve a fully type-safe way of doing this: your compiler may be able to match the DerivedInput when it sees a Derived object (static type), but it can not know what subtype is going to be behind a Base object...
The requirements
DerivedX should take a DerivedXInput
DerivedX::Foo should be interface-equal to DerivedY::Foo
contradict: either the Foo methods are implemented in terms of the BaseInput, and thus have identical interfaces in all derived classes, or the DerivedXInput types differ, and they cannot have the same interface.
That's, in my opinion, the problem.
This problem occured to me, too, when writing tightly coupled classes that are handled in a type-unaware framework:
class Fruit {};
class FruitTree {
virtual Fruit* pick() = 0;
};
class FruitEater {
virtual void eat( Fruit* ) = 0;
};
class Banana : public Fruit {};
class BananaTree {
virtual Banana* pick() { return new Banana; }
};
class BananaEater : public FruitEater {
void eat( Fruit* f ){
assert( dynamic_cast<Banana*>(f)!=0 );
delete f;
}
};
And a framework:
struct FruitPipeLine {
FruitTree* tree;
FruitEater* eater;
void cycle(){
eater->eat( tree->pick() );
}
};
Now this proves a design that's too easily broken: there's no part in the design that aligns the trees with the eaters:
FruitPipeLine pipe = { new BananaTree, new LemonEater }; // compiles fine
pipe.cycle(); // crash, probably.
You may improve the cohesion of the design, and remove the need for virtual dispatching, by making it a template:
template<class F> class Tree {
F* pick(); // no implementation
};
template<class F> class Eater {
void eat( F* f ){ delete f; } // default implementation is possible
};
template<class F> PipeLine {
Tree<F> tree;
Eater<F> eater;
void cycle(){ eater.eat( tree.pick() ); }
};
The implementations are really template specializations:
template<> class Tree<Banana> {
Banana* pick(){ return new Banana; }
};
...
PipeLine<Banana> pipe; // can't be wrong
pipe.cycle(); // no typechecking needed.
You might be able to use a variation of the curiously recurring template pattern.
class Base {
public:
// Stuff that don't depend on the input type.
};
template <typename Input>
class Middle : public Base {
public:
virtual void Foo(Input &i) = 0;
};
class Derived1 : public Middle<Derived1Input> {
public:
virtual void Foo(Derived1Input &i) { ... }
};
class Derived2 : public Middle<Derived2Input> {
public:
virtual void Foo(Derived2Input &i) { ... }
};
This is untested, just a shot from the hip!
If you don't mind the dynamic cast, how about this:
Class BaseInput;
class Base
{
public:
void foo(BaseInput & x) { foo_dispatch(x); };
private:
virtual void foo_dispatch(BaseInput &) = 0;
};
template <typename TInput = BaseInput> // default value to enforce nothing
class FooDistpatch : public Base
{
virtual void foo_dispatch(BaseInput & x)
{
foo_impl(dynamic_cast<TInput &>(x));
}
virtual void foo_impl(TInput &) = 0;
};
class Derived1 : public FooDispatch<Der1Input>
{
virtual void foo_impl(Der1Input & x) { /* your implementation here */ }
};
That way, you've built the dynamic type checking into the intermediate class, and your clients only ever derive from FooDispatch<DerivedInput>.
What you are talking about are covariant argument types, and that is quite an uncommon feature in a language, as it breaks your contract: You promised to accept a base_input object because you inherit from base, but you want the compiler to reject all but a small subset of base_inputs...
It is much more common for programming languages to offer the opposite: contra-variant argument types, as the derived type will not only accept everything that it is bound to accept by the contract, but also other types.
At any rate, C++ does not offer contravariance in argument types either, only covariance in the return type.
C++ has a lot of dark areas, so it's hard to say any specific thing is undoable, but going from the dark areas I do know, without a cast, this cannot be done. The virtual function specified in the base class requires the argument type to remain the same in all the children.
I am sure a cast can be used in a non-painful way though, perhaps by giving the base class an Enum 'type' member that is uniquely set by the constructor of each possible child that might possibly inherit it. Foo() can then check that 'type' and determine which type it is before doing anything, and throwing an assertion if it is surprised by something unexpected. It isn't compile time, but it's the closest a compromise I can think of, while still having the benefits of requiring a Foo() be defined.
It's certainly restricted, but you can use/simulate coviarance in constructors parameters.