I have a hirerchy of Message class and Processor class. Each processor can recieve one or more messages on the fly. As each message can have some differnt attributes, I've to downcast that message to the concrect message class, to actually process that.
As there are a no. of message classes and process classes, I don't want to use dynamic_cast.
I tried to use following code, but this is giving compile time error.
Also, I have the flexibility to attach a processor pointer with a message (if needed), but not the other way round.
class Message
{
public:
virtual const Message* const getMessage() const = 0;
};
class MA : public Message
{
public:
const MA* const getMessage() const {return this;}
void printMA() const{std::cout<<"I am MA"<<std::endl;}
};
class MB : public Message
{
public:
const MB* const getMessage() const {return this;}
void printMB() const{std::cout<<"I am MB"<<std::endl;}
};
class Processor
{
public:
virtual void process(const Message* m) = 0;
};
class PA : public Processor
{
public:
void process(const Message* m) {processM(m->getMessage());}
void processM(const MA* m) {m->printMA();}
void processM(const MB* m) {m->printMB();}
};
int main()
{
Message* m1 = new MA();
Message* m2 = new MB();
Processor* p1 = new PA();
p1->process(m1);
p1->process(m2);
return 0;
}
I used 'double dispatch' finally to get around this. Now, the only thing is that I need to add a function in MessageProcessor' class, whenever i add a new message type., but i think that is fine.
class MessageProcessor
{
public:
virtual void process(const MA*) const{std::cout<<"unhandled:MA"<<std::endl;}
virtual void process(const MB*) const{std::cout<<"unhandled:MB"<<std::endl;}
virtual void process(const MC*) const{std::cout<<"unhandled:MC"<<std::endl;}
};
class Message
{
public:
virtual void process(const MessageProcessor*) const = 0;
};
class MA : public Message
{
public:
void printMA() const{std::cout<<"I am MA"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class MB : public Message
{
public:
void printMB() const{std::cout<<"I am MB"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class MC : public Message
{
public:
void printMC() const{std::cout<<"I am MC"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class Processor : public MessageProcessor
{
public:
void processM(const Message* m){m->process(this);}
};
class PA : public Processor
{
public:
void process(const MA* m) const {m->printMA();}
void process(const MB* m) const {m->printMB();}
};
class PB : public Processor
{
public:
void process(const MA* m) const {m->printMA();}
void process(const MC* m) const {m->printMC();}
};
int main()
{
const Message* m1 = new MA();
const Message* m2 = new MB();
const Message* m3 = new MC();
Processor* p1 = new PA();
p1->processM(m1);
p1->processM(m2);
p1->processM(m3);
Processor* p2 = new PB();
p2->processM(m1);
p2->processM(m2);
p2->processM(m3);
return 0;
}
The most general solution to your problem is probably the Visitor pattern.
The simplest thing to do is eliminate the getMessage() method, and make the print() pure virtual in Message and override this in MA and MB. Furthermore, you can make process() a pure virtual method in Process and override this in PA. See code below:
#include <iostream>
class Message
{
public:
const std::string _id;
Message(std::string id):_id(id) {}
virtual void print() const = 0;
virtual void other_fun() const = 0;
};
class MA : public Message
{
private: double d_;
public:
MA():Message("MA"), d_(0.0) {}
virtual void print() const
{
std::cout<<"I am MA"<<std::endl;
std::cout << "I also have a double" << std::endl;
}
virtual void other_fun() const { std::cout << "I am MA specific" << std::endl; }
void do_hoops () const { std::cout << "Hoop!"<<std::endl;}
};
class MB : public Message
{
private: int i_;
public:
MB():Message("MB"), i_(0) {}
virtual void print() const
{
std::cout<<"I am MB"<<std::endl;
std::cout << "I also have an int"<<std::endl;
}
virtual void other_fun() const { std::cout << "I am MB specific" << std::endl; }
void do_twist() const { std::cout << "Twist!"<<std::endl; }
};
class Processor
{
public:
const std::string _id;
Processor(std::string id) : _id(id){}
virtual void process(const Message* m) = 0;
};
class PA : public Processor
{
public:
PA():Processor("PA") {}
virtual void process(const Message* m)
{
m->print();
m->other_fun();
}
};
int main()
{
Message* m1 = new MA();
Message* m2 = new MB();
// generic handling of message
Processor* p1 = new PA();
p1->process(m1);
p1->process(m2);
// message specific stuff
dynamic_cast<MA*>(m1)->do_hoops();
dynamic_cast<MB*>(m2)->do_twist();
return 0;
}
Output on Ideone.
No casts are required, the virtual functions will be selected at runtime through dynamic dispatch (virtual table lookup etc.). Message and Process are abstract base classes ("interfaces") and MA, MB and PA are concrete classes implementing these interfaces. Ideally, you also would factor the std::string state out of the Message interface, but that's left as an exercise.
Casting would be required if you would call functions that are specific to a derived class, and if you know at runtime that you are in fact calling such a class. This is done through a dynamic_cast to the particular derived class your base class pointer is currently pointing to.
You have a design flaw. Signature of Processor::process suggests it takes a Message, then it should not break this promise by trying to access something that is not a public interface of Message.
You can make Process a template class (host) that inherits from user supplied policies. Policies here are the concrete Message classes. Something like this:
#include <iostream>
struct MA
{
void print ()
{
std::cout << "MA: I'm the interface" << std::endl;
}
void printMA ()
{
std::cout << "MA: I'm special" << std::endl;
}
};
struct MB
{
void print ()
{
std::cout << "MB: I'm the interface" << std::endl;
}
void printMB ()
{
std::cout << "MB: I'm special" << std::endl;
}
};
template <typename M>
struct Process :
public M
{
void process()
{
M::print();
}
};
int main ()
{
Process<MA> p1;
Process<MB> p2;
p1.print(); // MA: I'm the interface
p1.printMA(); // MA: I'm special
p2.print(); // MB: I'm the interface
p2.printMB(); // MB: I'm special
}
Policies have print method that defines its interface. They also have some special methods like printMA and printMB. Host class (here Process) acts as user's interface to the policies. It can use the interface methods from policy classes. Special policy methods can be invoked by the user through host class.
You've run into a limitation of C++. What you really want is for the polymorphism to work on the arguments to a method, not just the method that the arguments are called on. It's generally referred to as double dispatch. Unfortunately, while there are some kind-of work-arounds, I haven't seen any perfect ones. That Wikipedia article shows the generally accepted workaround (using the Visitor pattern).
Related
I'm familiar with polymorphism in general, but I'm fairly new to C++ in general and templates in particular. I have to following situation with a mixture of code that I cannot change (usage of a framework, all events and templated event listeners) and code under my control (clients in the example below).
#include <string>
#include <iostream>
#include <vector>
class EventBase {
public:
virtual std::string getData() const = 0;
};
class EventA : public EventBase {
public:
std::string getData() const override {
return "Event A";
}
};
class EventB : public EventBase {
public:
std::string getData() const override {
return "Event B";
}
};
template<class T_Event>
class IEventHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
virtual void onError() = 0;
};
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
std::cout << "ClientA::onError" << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
class ClientB : public ClientBase, public IEventHandler<EventB> {
public:
void onEvent(const EventB& e) override {
std::cout << "ClientB::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
std::cout << "ClientB::onError" << std::endl;
};
void startReceiving() override {
std::cout << "ClientB::startReceiving" << std::endl;
};
};
int main(int, char**) {
//User Code
ClientA ca;
ClientB cb;
std::vector<ClientBase*> baseClients;
baseClients.push_back(&ca);
baseClients.push_back(&cb);
for(const auto client : baseClients){
client->startReceiving();
}
//Framework Code
EventA a;
EventB b;
std::vector<IEventHandler<EventA>*> eventHandlersA;
std::vector<IEventHandler<EventB>*> eventHandlersB;
eventHandlersA.push_back(&ca);
eventHandlersA[0]->onError();
eventHandlersA[0]->onEvent(a);
eventHandlersB.push_back(&cb);
eventHandlersB[0]->onError();
eventHandlersB[0]->onEvent(b);
//User Code
for(const auto client : baseClients){
client->stopReceiving();
}
}
See here: https://onlinegdb.com/2MYQhC2G5
What I want to do now is to have a common default implementation of onError.
To do so, I tried at least four approaches. Only the second worked. It would be nice to hear from C++ savants if this approach 2 is actually the way to do it.
Approach 1
Simply put onError in ClientBase and remove it from derived clients.
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Fails on compile time with
error: variable type 'ClientA' is an abstract class
note: unimplemented pure virtual method 'onError' in 'ClientA'
Okay, it's abstract since it does not implement the methods needed from IEventHandler<EventA>
Approach 2
Fix the unimplemented method in ClientA but call the super class method implementation:
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
ClientBase::onError();
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Works, though under the hood I think other things are happening then originally intended (might be more of a delegation then inheritance).
Maybe mess around with templates?
Approach 3: Remove the IEventHandler from the derived clients
class ClientBase : public IEventHandler<EventBase> {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
virtual void onEvent(const EventBase& e) = 0;
};
class ClientA : public ClientBase {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Build system hates me:
error: non-virtual member function marked 'override' hides virtual member function
note: hidden overloaded virtual function 'ClientBase::onEvent' declared here: type mismatch at 1st parameter ('const EventBase &' vs 'const EventA &')
error: variable type 'ClientA' is an abstract class
note: unimplemented pure virtual method 'onEvent' in 'ClientA' - virtual void onEvent(const EventBase& e) = 0;
Okay, so you can override methods only if the signature matches exactly.
Approach 4: Make ClientBase templated
template<class T_Event>
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
virtual void onEvent(const T_Event& e) = 0;
};
class ClientA : public ClientBase<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Again, no success. This time my structures to track my clients would break:
std::vector<ClientBase*> baseClients; ----> error: use of class template 'ClientBase' requires template arguments
eventHandlersA.push_back(&ca); ---> error: no matching member function for call to 'push_back'
Do you have any more ideas on how to achieve the original goal? Or is sticking to approach 2 a good solution?
Your insights into approaches 1-3 are generally correct:
Approach 1 failed because ClientBase didn't inherit from IEventHandler<> which declared the virtual method.
Approach 2 is indeed a delegation, which is fine in my opinion. Virtual methods are already a delegation - under the hood a vtable is roughly equivalent to a set of function pointers. Delegating onError is just one more level of indirection, and hopefully something called onError isn't called frequently enough to make the performance penalty significant.
Approach 3 failed because anything overriding onEvent(const EventBase& e) needs to accept any EventBase&, per the contract.
Approach 4 failed because ClientBase<EventA> and ClientBase<EventB> are completely different types that don't share a common base. Templates are more like type factories than types - there's no relationship between instantiations.
If you want to make the this work with inheritance, you can spell out that common base explicitly by having a non-template ClientBase and a template layer in between to implement onError:
template <typename TEvent>
class ErrorHandlingClient : public ClientBase, public IEventHandler<TEvent> {
public:
virtual void onError() override { /* ... */ }
};
class ClientA : public ErrorHandlingClient<EventA> {
public:
void onEvent(const EventA& e) override { /* ... */ }
void startReceiving() override { /* ... */ }
};
class ClientB : public ErrorHandlingClient<EventB> {
public:
void onEvent(const EventB& e) override { /* ... */ }
void startReceiving() override { /* ... */ }
};
ClientA and ClientB will have different implemenations of onError because of the template, but they can both be casted to a common ClientBase type to store in a vector.
One last opinion - if you need an abstract class to get your desired code organization, it might be a sign that your concerns aren't separated: Maybe IEventHandler<T> should really be two interfaces, or maybe error handling should be owned by some other entity.
The basic problem is having a class template with a virtual method that does not need the template parameter. It is not wrong per se, but it can easily make one's life mighty inconvenient.
The problem with your Approach 1 is having more than one source node in the inheritance graph that has errorHandler. These functions are unrelated. Here is a simplified demo:
struct X { virtual void foo() = 0; };
struct Y { virtual void foo() {} };
struct XY : X, Y {};
XY is still abstract, despite having an implementation of foo, because there are two unrelated foos in it and the only way to unify them is to override foo in XY. This surprises a lot of people.
The best practice here (as I understand it) is moving the offending function to a common base class of X, Y and XY (create one if needed). Up the hierarchy, not down or sideways. It should be inherited virtually (not a diamond-of-death problem, since it is an ABC with no data members).
So don't do this:
template<class T_Event>
class IEventHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
virtual void onError() = 0;
};
Do this instead:
class IErrorHandler {
public:
virtual void onError() = 0;
// or whatever default implementation you want
};
template<class T_Event>
class IEventHandler : public virtual /* XXX Important! */ IErrorHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
};
class ClientBase : public virtual IErrorHandler {
virtual void onError() override {} // whatever
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
virtual void onEvent(const EventA& e) {}
};
Live Demo.
Note, the MSVC compiler may issue a warning (C4250) on this. Ignore or silence it. For your convenience, here is a collection of SO posts on this topic.
I have a problem which I encounter again and again in a similar way.
For example:
I have an abstract base class which acts as interface for a series of concrete classes which act as, let's say, data containers.
class DataInterface
{
public:
DataInterface();
~DataInterface();
virtual void FetchData(void) = 0;
virtual void ProcessData(void) = 0;
virtual void ClearData(void) = 0;
}
The concrete classes would look like this:
class BinaryData: public DataInterface
{
public:
BinaryData();
~ BinaryData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
private:
bool m_boolData;
}
class IntegerData: public DataInterface
{
public:
IntegerData();
~ IntegerData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
private:
int m_intData;
}
The subclasses implement the interface which they inherited from DataInterface. But they have different attributes to hold their data. So far so good.
I can use the classes in the main function like that:
int main()
{
int IntegerData;
bool BoolData;
DataInterface *pData1 = new BinaryData();
DataInterface *pData2 = new IntegerData();
pData1->FetchData();
pData2->FetchData();
pData1->ProcessData();
pData2->ProcessData();
// now I want to get the data of pData1 and pData2, for example to write it into a file, show in visualization, ...
IntegerData = pData2->GetData() ????
BoolData = pData1->GetData() ????
}
Now comes the problem:
How do I get the data from the concrete classes? I have only base class pointers, so I would need to define an abstract getter method in DataInterface. But the signature of the getter method wouold vary from subclass to subclass. For example one time I need to return an integer, one time I need to return a bool type.
Please give me a hint, this problem drives me nuts :/
Make a non-virtual GetData() member on each derived class. Then, if you know for certain the actual class of your objects, you can simply perform a static cast and call GetData():
int intData = static_cast<IntegerData*>(pData2)->GetData();
If you don't know the class, then you need to perform a dynamic cast and check its result:
if (IntegerData* _pData2 = dynamic_cast<IntegerData*>(pData2))
{
int intData = _pData2->GetData();
// Do stuff with the int
}
else if (BinaryData* _pData2 = dynamic_cast<BinaryData*>(pData2))
{
bool binaryData = _pData2->GetData();
// Do stuff with the bool
}
If you want to pass your data to another entity, you need an abstraction of it.
There are 2 common ways to achieve this:
1:
Use void*.
class DataInterface
{
public:
...
virtual void* GetData() = 0;
};
class BinaryData: public DataInterface
{
public:
virtual void* GetData() { return &m_boolData; }
private:
bool m_boolData;
};
In main use it like this:
int main()
{
bool BoolData;
DataInterface *pData1 = new BinaryData();
pData1->FetchData();
pData1->ProcessData();
BoolData = *(bool*))pData1->GetData());
}
Advantage of this approach is in its simplicity.
Disadvantages are direct access to internal of an object (breaking encapsulation) and also misuse of polymorphism (why do you need an interface if you eventually cast to a type related to a concrete derivative?)
2:
A more robust way is to not send the raw data to a client from out of your concrete object but to make a communication with clients an additional role of the object.
class DataInterface
{
public:
...
virtual void SendData() = 0;
};
class BinaryData: public DataInterface
{
public:
...
virtual void SendData()
{
//do your stuff here, you know the exact type of your data
}
};
int main()
{
bool BoolData;
DataInterface *pData1 = new BinaryData();
pData1->FetchData();
pData1->ProcessData();
pData1->SendData();
}
Note, this is a very stripped example but it demonstrates the idea. Normally, in a real use case you would register clients with you class and send the data to them via a defined interface.
I am not really sure this is a "good" practice but here is one way to solve this.
One advantage with this is that if you try to get the wrong type of data you can get custom error messages. And you can avoid casts (I am not a fan of them).
class DataInterface
{
public:
DataInterface();
~DataInterface();
virtual void FetchData(void) = 0;
virtual void ProcessData(void) = 0;
virtual void ClearData(void) = 0;
virtual int getIntData() { // Error message }
virtual bool getBoolData() { // Error message }
};
class BinaryData: public DataInterface
{
public:
BinaryData();
~ BinaryData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
virtual int getIntData() { // Error message }
virtual bool getBoolData() { return m_boolData; }
private:
bool m_boolData;
}
class IntegerData: public DataInterface
{
public:
IntegerData();
~ IntegerData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
virtual int getIntData() { return m_intData; }
virtual bool getBoolData() { // Error message }
private:
int m_intData;
}
int main()
{
int IntegerData;
bool BoolData;
DataInterface *pData1 = new BinaryData();
DataInterface *pData2 = new IntegerData();
pData1->FetchData();
pData2->FetchData();
pData1->ProcessData();
pData2->ProcessData();
// now I want to get the data of pData1 and pData2, for example to write it into a file, show in visualization, ...
IntegerData = pData2->GetIntData();
BoolData = pData1->GetBoolData();
BoolData = pData2->GetBoolData() // This will tell you that you are trying to get bool from int class.
}
Here is one way of handling it with templates.
using namespace std;
template<typename T>
class DataInterface
{
public:
DataInterface(T d) : data(d) {}
virtual T GetData() = 0;
protected:
T data;
};
class BinaryData : public DataInterface<bool>
{
public:
BinaryData(bool b) : DataInterface<bool>(b) {}
virtual bool GetData() {return data;}
};
class IntegerData: public DataInterface<int>
{
public:
IntegerData(int i) : DataInterface<int>(i) {}
virtual int GetData() {return data;}
};
int main()
{
int myint;
bool mybool;
DataInterface<bool> *pData1 = new BinaryData(true);
DataInterface<int> *pData2 = new IntegerData(1);
// now I want to get the data of pData1 and pData2, for example to write it into a file, show in visualization, ...
myint = pData2->GetData();
mybool = pData1->GetData();
cout<<myint<<" "<<mybool<<endl;
}
A very simple way of achieving this is to design your base class so that it returns a variant type. A variant is a discriminated union container, which holds an object from an heterogeneous set of types (see http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html). Here is a complete example:
#include <iostream>
#include <algorithm>
#include <boost/variant.hpp>
#include <memory>
using namespace std;
class DataInterface
{
public:
DataInterface(){};
virtual ~DataInterface(){};
virtual void FetchData(void) = 0;
virtual void ProcessData(void) = 0;
virtual void ClearData(void) = 0;
virtual boost::variant<bool,int,double,std::string> GetData()=0;
};
class IntResult : public DataInterface{
public:
IntResult() : resultInt(0){};
~IntResult(){};
virtual void FetchData() override {resultInt = 10;};
virtual void ProcessData() override {resultInt *= 10;}
virtual void ClearData() override {resultInt = 0;};
virtual boost::variant<bool,int,double,std::string> GetData()override{
return resultInt;
};
private:
int resultInt;
};
class StringResult : public DataInterface{
public:
StringResult() : resultString(""){};
~StringResult(){};
virtual void FetchData() {
resultString= "Hello World";
}
virtual void ProcessData() override {
std::transform(resultString.begin(), resultString.end(),resultString.begin(), ::toupper);
}
virtual void ClearData() override {resultString = "";}
virtual boost::variant<bool,int,double,std::string> GetData() override {
return resultString;
};
private:
std::string resultString;
};
int main() {
DataInterface* data;
IntResult* intResult = new IntResult;
StringResult* stringResult = new StringResult;
data = intResult;
data->FetchData();
data->ProcessData();
switch(data->GetData().which()){
case 0:
std::cout << "found bool: " << boost::get<bool>(data->GetData()) << std::endl;
break;
case 1:
std::cout << "found int: " << boost::get<int>(data->GetData()) << std::endl;
break;
case 2:
std::cout << "found double: " << boost::get<double>(data->GetData()) << std::endl;
break;
case 3:
std::cout << "found string: " << boost::get<std::string>(data->GetData()) << std::endl;
break;
default:
break;
}
data = stringResult;
data->FetchData();
data->ProcessData();
switch(data->GetData().which()){
case 0:
std::cout << "found bool: " << boost::get<bool>(data->GetData()) << std::endl;
break;
case 1:
std::cout << "found int: " << boost::get<int>(data->GetData()) << std::endl;
break;
case 2:
std::cout << "found double: " << boost::get<double>(data->GetData()) << std::endl;
break;
case 3:
std::cout << "found string: " << boost::get<std::string>(data->GetData()) << std::endl;
break;
default:
break;
}
delete intResult;
delete stringResult;
return 0;
}
Note that in your case a bool is implicitly convertible to an int so you could simply return ints all the time. The variant approach would work if you need to return truly heterogeneous types. Equivalently you could return a boost any, which can also lets you manipulate a heterogeneous union of types uniformly (see http://www.boost.org/doc/libs/1_59_0/doc/html/any.html). Finally if you don't want any dependencies on boost, it is not terribly difficult to roll out your own variant type, which can hold discriminate set of types.
I have an object presented as a reference/pointer to an interface. I would like to call a method on the concrete object if that method is present, without changing the interface, breaking encapsulation, or writing any horrible hacks. How can it be done?
Here's an example.
I have an interface:
class IChatty
{
public:
virtual ~IChatty() {};
virtual std::string Speak() const = 0;
};
And multiple concrete implementation of this interface:
class SimpleChatty : public IChatty
{
public:
~SimpleChatty() {};
virtual std::string Speak() const override
{
return "hello";
}
};
class SuperChatty : public IChatty
{
public:
void AddToDictionary(const std::string& word)
{
words_.insert(word);
}
virtual std::string Speak() const override
{
std::string ret;
for(auto w = words_.begin(); w != words_.end(); ++w )
{
ret += *w;
ret += " ";
}
return ret;
}
private:
std::set<std::string> words_;
};
The SuperChatty::AddToDictionary method is not present in the abstract IChatty interface, although it could be included in another, new interface.
In the real world, these objects are constructed through factories, themselves concrete instantiations of an abstract interface. However for our purposes that's orthogonal to the problem at hand:
int main()
{
IChatty* chatty = new SuperChatty;
chatty->AddToDictionary("foo");
std::cout << chatty->Speak() << std::endl;
}
Since AddToDictionary isn't part of the IChatty interface (and can't be part of it), I can's call it.
How can I call AddToDictionary on the chatty pointer without breaking encapsulation, writing some horrible hack, or taking any other design shortcuts?
NOTE: In the real world, the dictionary is part of the SuperChatty object itself, and cannot be separate from it.
NOTE2: I do not want to downcast to the concrete type.
Have dictionary be an object which can be updated and referenced by SuperChatty:
class Dictionary {
public:
void add(const std::string& word);
const std::set<std::string>>& words() const;
//..
};
class SuperChatty : public IChatty
{
public:
SuperChatty(Dictionary& dictionary) :
dictionary(dictionary) {
}
virtual std::string Speak() const override
{
auto words = dictionary.words();
ostringstream oss;
copy(words.begin(), words.end(),
ostream_iterator<string>(oss, " "));
return oss.str();
}
};
Usage:
int main()
{
Dictionary dictionary;
IChatty* chatty = new SuperChatty(dictionary);
dictionary.add("foo");
std::cout << chatty->Speak() << std::endl;
}
edit
Okay, the question changed.
If you're doing this properly, you need to isolate yourself from the bad underlying system:
struct Dictionary {
virtual ~Dictionary () {}
virtual void add(const std::string& word) = 0;
};
struct Instrumenter {
virtual ~Instrumenter () {}
virtual void addDictionary(Dictionary& dictionary) = 0;
};
struct Chatter {
virtual ~Chatter() {}
virtual string speak() const = 0;
virtual void instrument(Instrumenter& instrumenter) = 0;
};
These are implemented as:
class BasicChatter : public Chatter {
virtual string speak() const {
return chatty.Speak();
}
virtual void instrument(Instrumenter& instrumenter) {
// do nothing
}
private:
SimpleChatty chatty;
};
class SuperChatter : public Chatter {
SuperChatter () : dictionary(chatty);
virtual void instrument(Instrumenter& instrumenter) {
instrumenter.addDictionary(dictionary);
}
virtual string speak() const {
return chatty.Speak();
}
private:
SuperChatty chatty;
DictionaryImpl dictionary;
};
Make it derive from another interface and simply check, whether you can cast the object to that interface or not.
class IDictionary
{
public:
virtual ~IDictionary() {};
virtual void AddToDictionary(const std::string& word) = 0;
};
class SuperChatty : public IChatty, public IDictionary
{
... as before ...
};
int main()
{
IChatty* chatty = new SuperChatty;
IDictionary *dict = dynamic_cast<IDictionary*>(chatty);
if (dict) dict->AddToDictionary("foo");
std::cout << chatty->Speak() << std::endl;
}
The main problem is that you're trowing away information that you need.
So the main solution is to not throw away information, but there's not enough code presented to flesh out the details of that.
Secondly, a tehcnical kludge solution is to just downcast, using dynamic_cast:
IChatty* newThingy();
int main()
{
IChatty* chatty = newThingy();
if( SuperChatty* p_super_chatty = dynamic_cast<SuperChatty*>( chatty ) )
{
p_super_chatty->AddToDictionary("foo");
}
std::cout << chatty->Speak() << std::endl;
}
You can downcast safely because the know static type IChatty is polymorphic.
For this particular example, there's no reason to not create the object as this:
SuperChatty* chatty = new SuperChatty;
chatty->AddToDictionary("foo");
You can still pass chatty in the above segment as IChatty pointer or reference, e.g.
void Talk(IChatty *ch)
{
ch->Speak();
}
[Likewise for storing the chatty in a vector<IChatty*> or something like that].
My point here is that if you are going to use the "new" interface functions, then you probably also want to create the class that has the new interface.
Adding code to "try to cast it", etc, gets very messy very quickly, and is error prone.
Edit: Per some comments, by simple I mean a) less code, b) easy to maintain, and c) hard to get wrong.
Edit #2: Also, using containment instead of private inheritance is not objectionable if it does indeed simplify the implementation of InterfaceImpl.
Currently, the only way I know to do this is to have the implementer define the abstract method and delegate the call to the target base type's method. Example:
#include <iostream>
#include <memory>
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
class MethodOneImpl
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
class MethodTwoImpl
{
public:
void myFunc(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
class InterfaceImpl : public Interface
, private MethodOneImpl
, private MethodTwoImpl
{
public:
virtual void method1() { MethodOneImpl::method1(); }
virtual void method2(int x) { MethodTwoImpl::myFunc(x); }
};
int main()
{
std::unique_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf->method2(0);
// This should be disallowed!
// std::unique_ptr<MethodOneImpl> moi;
// moi.reset(new InterfaceImpl);
}
At first, I thought that perhaps this might solve the problem:
class InterfaceImpl : public Interface
, private MethodOneImpl
, private MethodTwoImpl
{
public:
using MethodOneImpl::method1;
// Obviously this wouldn't work as the method names don't match.
//using MethodTwoImpl::???
};
The first using statement will make both MethodOneImpl::method1 methods be public, but it actually doesn't fulfill the contract with Interface, and it modifies the accessibility of MethodOneImpl::method1(int). And obviously we couldn't use this solution with method2 as the names don't match up.
FWIW, I have what I think is a solution, but it is not part of the standard at all (in other words it won't compile). I was thinking of making a proposal to the C++ committee; if anyone has any advice, I'd appreciate any comments below (but please dont' submit the advice as an answer).
An other option (at least if using MS VC++) is to use virtual inheritance:
struct MyInterface
{
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class Method1Impl : public virtual MyInterface
{
virtual void Method1() { _tprintf( _T("Method1\n") ); }
};
class Method2Impl : public virtual MyInterface
{
virtual void Method2() { _tprintf( _T("Method2\n") ); }
};
class InterfaceImpl : public virtual MyInterface,
private Method1Impl,
private Method2Impl
{
};
void TestWeirdInterfaceImpl()
{
MyInterface* pItf = new InterfaceImpl();
pItf->Method1();
pItf->Method2();
}
While this seems to work and satisfy what you are looking for (asside from C4250 warning that you will have to suppress with a #pragma), this wouldn't be my approach. (I believe virtual inheritance is still not something that supported across all compilers, but I could be wrong).
I would probably go with containment and once boilerplate code is identifier, wrap it into some kind of macro map (similar to maps in ATL or MFC) that would make it really, really difficult to ever screw it up.
So this would be my macro approach:
struct MyInterface
{
virtual float Method1( int x ) = 0;
virtual int Method2( float a, float b ) = 0;
virtual void Method3( const TCHAR* sz ) = 0;
};
class Method1Impl
{
public:
float Method1( int x ) {
_tprintf( _T("Method1: %d\n"), x ); return 5.0;
}
};
class Method2and3Impl
{
public:
int Method2( float a, float b ) {
_tprintf( _T("Method2: %f, %f\n"), a, b ); return 666;
}
void Method3( const TCHAR* sz ) {
_tprintf( _T("Method3: %s"), sz );
}
};
#define DECLARE_METHOD0( MethodName, Obj, R ) \
virtual R MethodName() { return Obj.MethodName(); }
#define DECLARE_METHOD1( MethodName, Obj, R, A1 ) \
virtual R MethodName( A1 a1 ) { return Obj.MethodName( a1 ); }
#define DECLARE_METHOD2( MethodName, Obj, R, A1, A2 ) \
virtual R MethodName( A1 a1, A2 a2 ) { return Obj.MethodName( a1, a2 ); }
class InterfaceImpl : public MyInterface
{
public:
DECLARE_METHOD1( Method1, m_method1Impl, float, int );
DECLARE_METHOD2( Method2, m_method2and3Impl, int, float, float );
DECLARE_METHOD1( Method3, m_method2and3Impl, void, const TCHAR* );
private:
Method1Impl m_method1Impl;
Method2and3Impl m_method2and3Impl;
};
void TestWeirdInterfaceImpl()
{
MyInterface* pItf = new InterfaceImpl();
pItf->Method1( 86 );
pItf->Method2( 42.0, 24.0 );
pItf->Method3( _T("hi") );
}
Until C++ gods grace us with variadic macros, you'll have to declare one for each number of parameters you have. Also if you used multiple inheritance, potentially you wouldn't need the second "Obj" param, but as I've said before, I'd avoid multiple inheritance if there's another solution, which in this case is one extra param.
Yet a third option could be something that authors of Pragmatic Programmer seem to advocate a lot. If you have a ton of cookie cutter code that you don't want to repeat because, as you pointed out, it introduces human error. Define your own language and write a code generator script (python, perl...) to auto-create the actual code. In this case you could almost point at an interface, and have the script write the text out for you. I haven't tried doing this kind of thing myself, but lately have been wanting to use it somewhere just to see and evaluate the outcome.
This is sort of ugly and may bloat the executable size, but what about
#include <iostream>
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
template<typename T>
class MethodOneImpl : public T
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
template<typename T>
class MethodTwoImpl : public T
{
public:
void method2(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
class InterfaceImpl : public MethodTwoImpl<MethodOneImpl<Interface> >
{
};
int main()
{
InterfaceImpl impl;
impl.method1();
impl.method2(0);
}
class AbsInterface
{
// this is a simple interface class.
public:
virtual void Method1() = 0;
virtual void Method2() = 0;
};
class Functor1
{
public:
void operator () ()
{
printf("This Is Void Functor1");
}
};
class Functor2
{
public:
void operator () ()
{
printf("This Is void Functor2");
}
};
template <class T1, class T2>
class DerivedTemplateClass : public AbsInterface
{
public:
virtual void Method1() { T1()(); }
virtual void Method2() { T2()(); }
};
void main()
{
DerivedTemplateClass<Stratege1, Stratege2> instance;
instance.Method1();
instance.Method2();
}
as you can see, I used Functor.
You could work with template and functor.
It seems impossible to bring MethodOneImpl / MethodTwoImpl into the scope of Interface without having them inherit from Interface because they will not fill the Virtual Table if they don't. C++ misses something like the keyword implements from other languages.
So you are stuck with the virtual inheritence thing unless realize/accept that what you are looking for is just a bridge pattern, which does not satisfy requirement a) (you shall write more code), midly b) (code not necessarly difficult to maintain) and may satisfy c).
Here (another) possible solution (with only method though to reduce bloat)
class Interface
{ public:
virtual void method1() {return impl_->method1();}
private:
Interface() {}
protected:
struct Impl {
virtual void method1() = 0; };
std::shared_ptr<Impl> impl_;
Interface(const std::shared_ptr<Impl> &impl) : impl_(impl) {}
};
class InterfaceImpl : public Interface
{
struct Impl : public Interface::Impl {
void method1() { std::cout << "InterfaceImpl::method1() " << std::endl; } } ;
public:
InterfaceImpl() : Interface(std::shared_ptr<Impl> (new Impl)) {}
};
template <class T>
class GenericInterfaceImpl : public Interface {
struct Impl : public Interface::Impl {
Impl( T &t) : t_(t) {}
void method1() { t_.method1() ; }
T t_; };
public:
GenericInterfaceImpl() : Interface(std::shared_ptr<Impl> (new Impl(T()))) {}
};
struct AMethod1Impl {
void method1() { std::cout << "AMethod1Impl::method1() " << std::endl; } } ;
struct AnotherMethod1Impl_not_working {
void method1_not_present() { std::cout << "AnotherMethod1Impl_not_working ::method1_not_present() " << std::endl; } } ;
int main() {
// compilation of next line would fail
// (lame attempt to simulate ompilation fail when pure function not implemented)
// Interface inf;
std::unique_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf.reset(new GenericInterfaceImpl<AMethod1Impl>() );
inf->method1();
// compilation of next line would fail
// inf.reset(new GenericInterfaceImpl<AnotherMethod1Impl_not_working>() );
}
Does this serve your purpose?
It maintains the interface relationship and gives you maintainable code without having any consideration of client code.
Separating each method in functionoid and giving you the power to control the prototype of each method of the different base class.
#include <iostream>
#include <memory>
using namespace std;
//No Control over this.
class MethodOneImpl
{
private:
void method1(int x)
{ std::cout << "MethodOneImpl::method1() " << x << std::endl; }
public:
void method1() { method1(0); }
};
class MethodTwoImpl
{
public:
void myFunc(int x)
{ std::cout << "MethodTwoImpl::myFunc(x)" << x << std::endl; }
};
//*************************//
class Interface
{
public:
virtual void method1() = 0;
virtual void method2(int x) = 0;
};
//This is what i would do. //
class BaseFuncType
{
//no pure virtual
void Call()
{
throw "error";
}
void Call(int x)
{
throw "error";
}
};
class Method1: public BaseFuncType
{
auto_ptr<MethodOneImpl> MethodPtr;
public:
Method1()
{
MethodPtr.reset(new MethodOneImpl());
}
virtual int Call()
{
MethodPtr->method1();
}
};
class Method2: public BaseFuncType
{
auto_ptr<MethodTwoImpl> MethodPtr;
public:
Method2()
{
MethodPtr.reset(new MethodTwoImpl());
}
virtual int Call(int x)
{
MethodPtr->myFunc(x);
}
};
template <class T1>
class MethodFactory
{
private:
T1 methodObj;
public:
void CallMethod()
{
methodObj.Call();
}
void CallMethod(int x)
{
methodObj.Call(x);
}
};
class InterfaceImpl : public Interface
{
auto_ptr<MethodFactory> factory;
public:
virtual void method1()
{
factory.reset(new MethodFactory<Method1>());
factory->CallMethod();
}
virtual void method2(int x)
{
factory.reset(new MethodFactory<Method2>());
factory->CallMethod(x);
}
};
int main()
{
auto_ptr<Interface> inf;
inf.reset(new InterfaceImpl);
inf->method1();
inf->method2(10);
// This should be disallowed!
// std::unique_ptr<MethodOneImpl> moi;
// moi.reset(new InterfaceImpl);
}
I've currently got a class that can notify a number of other objects via callbacks:
class Callback {
virtual NodulesChanged() =0;
virtual TurkiesTwisted() =0;
};
class Notifier
{
std::vector<Callback*> m_Callbacks;
void AddCallback(Callback* cb) {m_Callbacks.push(cb); }
...
void ChangeNodules() {
for (iterator it=m_Callbacks.begin(); it!=m_Callbacks.end(); it++) {
(*it)->NodulesChanged();
}
}
};
I'm considering changing this to use boost's signals and slots as it would be beneficial to reduce the likelihood of dangling pointers when the callee gets deleted, among other things. However, as it stands boost's signals seems more oriented towards dealing with function objects. What would be the best way of adapting my code to still use the callback interface but use signals and slots to deal with the connection and notification aspects?
Compared to my other answer, this solution is much more generic and eliminates boilerplate code:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/signal.hpp>
///////////////////////////////////////////////////////////////////////////////
// GENERIC REUSABLE PART FOR ALL SUBJECTS
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
template <class CallbackType>
class CallbackInvoker
{
public:
virtual ~CallbackInvoker() {}
virtual void operator()(CallbackType* callback) const {};
};
//-----------------------------------------------------------------------------
template <class CallbackType, class Binding>
class BoundInvoker : public CallbackInvoker<CallbackType>
{
public:
BoundInvoker(const Binding& binding) : binding_(binding) {}
void operator()(CallbackType* callback) const {binding_(callback);}
private:
Binding binding_;
};
//-----------------------------------------------------------------------------
template <class CallbackType>
class CallbackSlot
{
public:
CallbackSlot(CallbackType* callback) : callback_(callback) {}
void operator()(const CallbackInvoker<CallbackType>& invoker)
{invoker(callback_);}
private:
CallbackType* callback_;
};
//-----------------------------------------------------------------------------
template <class CallbackType>
class Subject
{
public:
virtual ~Subject() {}
boost::signals::connection Connect(CallbackType* callback)
{return signal_.connect(CallbackSlot<CallbackType>(callback));}
protected:
template <class Binding> void Signal(const Binding& binding)
{
signal_(BoundInvoker<CallbackType,Binding>(binding));
}
private:
boost::signal<void (const CallbackInvoker<CallbackType>&)> signal_;
};
///////////////////////////////////////////////////////////////////////////////
// THIS PART SPECIFIC TO ONE SUBJECT
///////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
class MyCallback
{
public:
virtual ~MyCallback() {}
virtual void NodulesChanged() =0;
virtual void TurkiesTwisted(int arg) =0;
};
//-----------------------------------------------------------------------------
class FooCallback : public MyCallback
{
public:
virtual ~FooCallback() {}
void NodulesChanged() {std::cout << "Foo nodules changed\n";}
void TurkiesTwisted(int arg)
{std::cout << "Foo " << arg << " turkies twisted\n";}
};
//-----------------------------------------------------------------------------
class BarCallback : public MyCallback
{
public:
virtual ~BarCallback() {}
void NodulesChanged() {std::cout << "Bar nodules changed\n";}
void TurkiesTwisted(int arg)
{std::cout << "Bar " << arg << " turkies twisted\n";}
};
//-----------------------------------------------------------------------------
class MySubject : public Subject<MyCallback>
{
public:
void OnNoduleChanged()
{this->Signal(boost::bind(&MyCallback::NodulesChanged, _1));}
void OnTurkiedTwisted(int arg)
{this->Signal(boost::bind(&MyCallback::TurkiesTwisted, _1, arg));}
};
///////////////////////////////////////////////////////////////////////////////
// CLIENT CODE
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
int main()
{
MySubject subject;
FooCallback fooCb;
BarCallback barCb;
subject.Connect(&fooCb);
subject.Connect(&barCb);
subject.OnNoduleChanged();
subject.OnTurkiedTwisted(42);
}
Hooray for boost::bind! :-)
boost::signals is pretty flexible when it comes to what you bind to a signal. You can use a function object, but you can also just use a function pointer or use boost::bind to make almost any kind of function into a function object. Here is what your example might look like, although there may be better ways.
#include <boost/signals.hpp>
class Notifier
{
public:
boost::signal< void() > NodulesChanged;
void ChangeNodules()
{
//Just call the signal and all connected slots will be called.
NodulesChanged();
}
};
To add a callback, you can simply
void callback1()
{
//do callback stuff
}
void callback2()
{
//do callback stuff
}
int main()
{
Notifier n;
n.NodulesChanged.connect(&callback1);
n.NodulesChanged.connect(&callback2);
//calls callback1 & 2.
n.ChangeNodules();
}
If you wanted to connect a member function with arguments as a slot, you could do something like this:
class Notifier
{
public:
boost::signal< void ( double ) > ProgressSignal;
};
class OtherClass
{
public:
void UpdateProgress(double pct);
};
int main()
{
Notifier n;
OtherClass oc;
n.ProgressSignal.connect(boost::bind(&OtherClass::UpdateProgress, &oc, _1));
//Calls oc.UpdateProgress(0);
n.ProgressSignal(0);
}
Warning: None of this has been compiled or tested.
This solution allows you to use the same signal object even if Callback's methods have different signatures.
#include <iostream>
#include <boost/signal.hpp>
//------------------------------------------------------------------------------
class Callback
{
public:
virtual void NodulesChanged() =0;
virtual void TurkiesTwisted(int arg) =0;
};
//------------------------------------------------------------------------------
class FooCallback : public Callback
{
public:
void NodulesChanged() {std::cout << "Foo nodules changed\n";}
void TurkiesTwisted(int arg) {std::cout << "Foo " << arg << " turkies twisted\n";}
};
//------------------------------------------------------------------------------
class BarCallback : public Callback
{
public:
void NodulesChanged() {std::cout << "Bar nodules changed\n";}
void TurkiesTwisted(int arg) {std::cout << "Bar " << arg << " turkies twisted\n";}
};
//------------------------------------------------------------------------------
class CallbackInvoker
{
public:
virtual void operator()(Callback* callback) const {};
};
//------------------------------------------------------------------------------
class NoduleChangedInvoker : public CallbackInvoker
{
public:
void operator()(Callback* callback) const {callback->NodulesChanged();}
};
//------------------------------------------------------------------------------
class TurkiesTwistedInvoker : public CallbackInvoker
{
public:
TurkiesTwistedInvoker(int arg) : arg_(arg) {}
void operator()(Callback* callback) const {callback->TurkiesTwisted(arg_);}
private:
int arg_;
};
//------------------------------------------------------------------------------
class CallbackSlot
{
public:
CallbackSlot(Callback* callback) : callback_(callback) {}
void operator()(const CallbackInvoker& invoker) {invoker(callback_);}
private:
Callback* callback_;
};
//------------------------------------------------------------------------------
class Subject
{
public:
typedef boost::signal<void (const CallbackInvoker&)> SignalType;
boost::signals::connection Connect(Callback* callback)
{return signal_.connect(CallbackSlot(callback));}
void OnNoduleChanged() {signal_(NoduleChangedInvoker());}
void OnTurkiedTwisted(int arg) {signal_(TurkiesTwistedInvoker(arg));}
private:
SignalType signal_;
};
//------------------------------------------------------------------------------
int main()
{
Subject subject;
FooCallback fooCb;
BarCallback barCb;
subject.Connect(&fooCb);
subject.Connect(&barCb);
subject.OnNoduleChanged();
subject.OnTurkiedTwisted(42);
}
This outputs:
Foo nodules changed
Bar nodules changed
Foo 42 turkies twisted
Bar 42 turkies twisted
CallbackSlot is the function object stored in the boost::signal, and contains a pointer to a concrete Callback object. When you invoke the boost::signal, you have to pass it a CallbackInvoker concrete object which bundles any callback arguments and which knows how to invoke the appropriate Callback method.
There might be a way to avoid the CallbackInvoker boilerplate code using Boost.Lamda, but I'm not very familiar with that Boost library.
You'll probably want to use boost::shared_ptr<Callback> instead of Callback* to avoid memory leaks and dangling pointers.