Here is my MESSAGE structure:
struct tEventMessage
{
// Type of the event
int Type;
// (void*) Allows those to be casted into per-Type objects
void *pArgument1;
void *pArgument2;
};
Can i add some kind of 'template' member to this structure, so that later on when building message i can pass those pointers + and any other data i wish ? ( see example below )
struct tEventMessage
{
// Type of the event
int Type;
// (void*) Allows those to be casted into per-Type objects
void *pArgument1;
void *pArgument2;
// Template
T tSomeTemplateMember;
};
void HandleClick(....)
{
CVector3 vNewPosition = ....
tEventMessage _msg;
_msg.Type = xxxx;
_msg.pArgument1 = pA->GetObjectPointer();
//
// Wrong!
// Because this CVector3 will not be alive in next tick
// - my pointer will point to nothing.
//
_msg.pArgument2 = static_cast<CVector3*>(&vNewPosition)
//
// Something like that would be great
// And would allow me to use CVector2,CVector3,CVector4 with one template member
//
_msg.tSomeTemplateMember = vNewPosition;
}
I think you're over complicating the problem. Instead of one problem, how to pass arbitrary data in a message, you now have two, how to cope with templates as well.
The usual method to implement this sort of thing is to use inheritance:-
class Message
{
public:
int Type () { return type; }
protected:
int type;
};
class ClickMessage : public Message
{
public:
ClickMessage () { type = ClickMessageID; }
private:
// the message data
};
void HandleMessage (Message *message)
{
switch (message->Type ())
{
case ClickMessageID:
HandleClick (reinterpret_cast <ClickMessage *> (message));
break;
default:
// unhandled message error
break;
}
}
void HandleClick (ClickMessage *message)
{
// do stuff
}
The problem is you end up repeating a lot of code, i.e the cast in the switch statement. There's also a maintenance issue too - added new messages requires a bit of careful updating. You could hack the code a bit and use function pointers and a map to convert message types to functions and replace the switch statement.
There might be a clever template solution, but I can't think what it might be.
Using RTTI might help (at a cost).
This is one problem that reflection is really good at solving!
Perhaps I am missing something however I am wondering why you do not start with an abstract class from which you then derive your various kinds of event messages. By taking advantage of abstract classes and deriving classes from them, you let the compiler figure out the logic that you are using a switch statement for. See this C++ Polymorphism and Abstract Base Class tutorial.
Also see this from MSDN on Abstract classes.
For instance you might have an abstract class that looks like the following. However you may not want as much of this and in fact may just want the single processEvent() method only. Any derived classes will need to provide their own versions of each of the functions specified in the abstract class.
class EventMessage abstract {
public:
virtual void *getArgument1 (void) = 0;
virtual void *getArgument2 (void) = 0;
virtual int processEvent (void) = 0;
protected:
void *pArgument1;
void *pArgument2;
};
What this abstract class defines is a class that basically contains the data that is used by all of the various event messages along with a method that is called to process the the actual message. The class itself is not instantiated however it is used as the parent or super class for other derived class that are actually instantiated as objects.
What you would then do is to derive new classes that would implement the EventMessage interface. For instance here are two different classes that would do that:
class JoJoEvent : public EventMessage {
public:
JoJoEvent(void *arg1, void *arg2);
void *getArgument1 (void);
void *getArgument2 (void);
int processEvent (void);
};
JoJoEvent::JoJoEvent(void *arg1, void *arg2)
{
pArgument1 = arg1;
pArgument2 = arg2;
}
void * JoJoEvent::getArgument1 (void) {
return pArgument1;
}
void * JoJoEvent::getArgument2 (void) {
return pArgument2;
}
int JoJoEvent::processEvent (void) {
// do stuff with the arguments
return 1;
}
class KoKoEvent : public EventMessage {
public:
KoKoEvent(void *arg1, void *arg2);
void *getArgument1 (void);
void *getArgument2 (void);
int processEvent (void);
};
KoKoEvent::KoKoEvent(void *arg1, void *arg2)
{
pArgument1 = arg1;
pArgument2 = arg2;
}
void * KoKoEvent::getArgument1 (void) {
return pArgument1;
}
void * KoKoEvent::getArgument2 (void) {
return pArgument2;
}
int KoKoEvent::processEvent (void) {
// do stuff with the arguments
return 1;
}
Then when using these you would do something like the following code:
EventMessage *myMessage = new JoJoEvent(0, 0);
EventMessage *myMessage2 = new KoKoEvent(0, 0);
myMessage2->processEvent();
myMessage->processEvent();
If you need to add additional data into the derived classes you can do so just provide a mechanism to put the data into the derived class.
Related
I’m running on Wintel and I want to be able to call a variable method of any object as long as I know the method signature. Is the following assembler correct? Do I need to save/restore ECX? It seems to work but I want to know if I’m missing something. Yeah, yeah, say goodbye type safety, danger is my middle name...
So, why would I want to do this? I have a message distribution system. Business logic subscribes for messages and the distribution system hands them out when they come in. Right now I’m using an interface definition. I have business objects that need to receive multiple message types. Each handler function has a block of if-else statements to figure out the message type. I would like a single class to subscribe to multiple message types and have different methods for each type. I could switch to function pointers, but then I’d have a bunch of static methods and non-static counter parts.
It’s only 3 assembler instructions, how bad could it be?? Looks down the slippery slope
#include <stdio.h>
class A {
public:
A(int i){
m_i = i;
}
void test(int i){
printf("m_i = %i, i = %i\n",m_i,i);
}
private:
int m_i;
};
void callmethod(void *object, const void *function, int i){
__asm {
push [i];
mov ecx, object;
call function;
}
}
int main(){
A a(123);
callmethod(&a,_ADDRESSOF(A::test),456);
return 0;
}
Outputs:
m_i = 123, i = 456
Here's a more detailed example of what I have now and comments explaining what I would like to do.
#include <stdio.h>
#include <unordered_map>
#include <list>
using std::unordered_map;
using std::list;
class IMessage {
};
class MessageHandler {
public:
virtual ~MessageHandler(){}
virtual void HandleMessage(int type, IMessage *message) = 0;
};
class MessageDispatcher {
public:
void Subscribe(int type, MessageHandler *callback){
m_callbacks[type].push_back(callback);
}
void ProcessMessage(int type, IMessage *message){
if (m_callbacks.find(type) != m_callbacks.end()){
list<MessageHandler*> &callbacks = m_callbacks[type];
for (list<MessageHandler*>::iterator i = callbacks.begin(); i != callbacks.end(); ++i){
(*i)->HandleMessage(type,message);
}
}
}
private:
unordered_map<int,list<MessageHandler*> > m_callbacks;
};
class BusinesLogic : public MessageHandler {
public:
BusinesLogic(MessageDispatcher *md){
md->Subscribe(0,this); // I want to put HandleType0 here like this
// md-Subscribe(0,this,HandleType0);
md->Subscribe(1,this); // I want to put HandleType1 here like this
// md-Subscribe(1,this,HandleType1);
}
private:
void HandleType0(IMessage *message){
printf("Got type 0\n");
}
void HandleType1(IMessage *message){
printf("Got type 1\n");
}
virtual void HandleMessage(int type, IMessage *message){
// I want to do away with this switch block and let the MessageDispatcher
// class call into the HandleType0 and HandleType1 methods directly
// without using static methods
switch (type){
case 0:
HandleType0(message);
break;
case 1:
HandleType1(message);
break;
}
}
};
int main(){
MessageDispatcher md;
BusinesLogic bl(&md);
md.ProcessMessage(0,nullptr);
md.ProcessMessage(1,nullptr);
return 0;
}
You want to use pointers to members like Kay suggested in his first comment.
A simple way do this would be something like the following example:
virtual void HandleMessage(int type, IMessage *message){
typedef void (BusinesLogic::*handler_mfn_type)(IMessage *);
static const handler_mfn_type dispatch_table[] = {
&BusinesLogic::HandleType0,
&BusinesLogic::HandleType1
};
handler_mfn_type mfn = dispatch_table[type];
(this->*mfn)(message);
}
No inline assembler and no static functions. No subscribing to the methods themselves either, but I'm not sure if that's a bad thing.
If you really want to be able to pass the method in the Subscribe call then you'll need to wrap it in a class that bundles the (pointer to) method with a pointer to the object. There's no escaping the fact that you need both to invoke a method.
Create a base class and a template like this:
class callback_base {
public:
virtual void call_handler(IMessage *) = 0;
};
template <class T>
class callback: public callback_base {
typedef void (T::*mfn_type)(IMessage *);
T *obj;
mfn_type mfn;
public:
callback(T *a, mfn_type b): obj(a), mfn(b) {}
virtual void call_handler(IMessage *msg) {
(obj->*mfn)(msg);
}
};
And use it like this:
md->Subscribe(0,new callback<BusinesLogic>(this, &BusinesLogic::HandleType0));
md->Subscribe(1,new callback<BusinesLogic>(this, &BusinesLogic::HandleType1));
void Subscribe(int type, callback_base *cb){
m_callbacks[type].push_back(cb);
}
void ProcessMessage(int type, IMessage *message){
...
for (list<callback_base *>::iterator i = callbacks.begin(); i != callbacks.end(); ++i){
(**i).call_handler(message);
}
In the following exceedingly abbreviated classes I would like to define in the base a method (ProcessLines) that would iterate over a set of database records, passing each record as a parameter to a function that is only defined in the child class. Obviously the Base is a virtual class that will never be instantiated on its own.
Class Base {
public:
typedef ProcLineFunc( Long *Line );
void ProcessLines( ProcLineFunc pf);
}
Class Child{
void DoWork( Long *Line) { //do something}
}
I'm not sure how to implement this. If I redeclare ProcessLines in the child and just call the parent method, I get the same error message as if I call ProcessLines in the code that creates the child.
Child c(//something);
c.ProcessLines(c.DoWork);
Gives me a compiler message:
[BCC32 Error] main.cpp(67): E2034 Cannot convert 'bool (* (_closure )(long *))(long )' >to 'int ()(long *)'
Full parser context
main.cpp(56): class Add2Chan
main.cpp(78): decision to instantiate: bool Add2Chan::ProcessByLines()
--- Resetting parser context for instantiation...
main.cpp(67): parsing: bool Add2Chan::ProcessByLines()
I'm fairly new to c++ and the E2034 error message scares the daylights out of me.
Please help. I used a typedef so that I can, in my child classes call ProcessLines multiple times, passing in different functions as I go.
Normally you would do this sort of thing with a protected, pure virtual function:
class Base {
public:
ProcessLines() {
//Logic to process lines here, obviously psuedo-code
while(moreLines) {
ProcessLine(line);
}
}
protected:
virtual void ProcessLine(const Line& line) = 0;
}
class Child : public Base {
protected:
void ProcessLine(const Line& line) { //Logic to process the line for this type }
};
class DifferentChild : public Base {
protected:
void ProcessLine(const Line& line) { //Logic to process the line for DifferentChild }
};
I think this is the kind of thing you're looking for. It appears to me like you're trying to implement polymorphism in an odd way, but this is the normal way to do it in C++.
Instead of using pointers to functions, use pointers to objects. Accept the limitation that your function is going to be called DoWork and nothing else, and there can only be one such function in each class. This is not a bad limitation. Declare the (pure virtual) function in a class (which is called an interface), and derive classes from it (they are said to implement an interface).
struct DoingWork
{
virtual void DoWork(long *Line) = 0; // does some work on a list
};
struct DoingGreatWork: DoingWork
{
virtual void DoWork(long *Line) {printf("Great work\n");}
};
struct DoingSlightWork: DoingWork
{
virtual void DoWork(long *Line) {printf("Slight work\n");}
};
Using this example:
class Base {
public:
void ProcessLines(DoingWork& object) {
//Logic to process lines here
while(moreLines) {
object.DoWork(line);
}
}
};
class Whatever // no need to derive from Base
{
void DoStuff()
{
Base object;
object.ProcessLines(DoingGreatWork());
object.ProcessLines(DoingSlightWork());
}
}
If the working objects have to have access to the calling object, initialize them like this:
class Whatever // no need to derive from Base
{
struct DoingElaborateWork: DoingWork
{
Whatever& caller;
DoingElaborateWork(Whatever& caller): caller(caller) {}
virtual void DoWork(long *Line)
{
printf("Doing work requested by %s\n", caller.name());
}
};
void DoStuff()
{
Base object;
object.ProcessLines(DoingElaborateWork(*this));
}
const char* name() {return "Whatever";}
}
P.S. They say that "in C++03 functions are second-class citizens" because you cannot do with functions what you can do with objects (like this solution i provide). I heard that in C++11 functions are much improved, but i am not sure about the details.
Since you are doing this in C++Builder, you can utilize its __closure extension to do exactly what you asked for (some portions of the VCL do exactly this for their own callbacks):
class Base
{
public:
virtual ~Base() {}
typedef void (__closure *ProcLineFunc)( Long *Line );
void ProcessLines( ProcLineFunc pf);
};
class Child : public Base
{
public:
void DoWork( Long *Line) { //do something}
};
Child c(...);
c.ProcessLines(c.DoWork);
In my design, there is a class which reads information from file. The read info represents a job (for simplicity, it's an integer, which is "job id"). The file reader class can accept objects which can handle such a job. Now my idea was, to make an Interface, e.g. "IJobHandler" which has a pure virtual function "DoJob()" and then you can call something like
FileReader fr;
Class1 c1; // has a base class IAcceptor with virtual method HandleJobId()
Class2 c2; // has a base class IAcceptor with virtual method HandleJobId()
fr.Register(c1);
fr.Register(c2);
fr.doJob(1); // calls c1.HandleJobId()
fr.doJob(2); // class c2.HandleJobId()
This would work fine. But what happens, if some class can handle two or more job ids? But there is only one method which this class can implement (HandleJobId()). Wouldn't the following be nice:
fr.Register(c1, c1::Handle_1()) or something like that?
Maybe my intention is not very clear right now. But you will se it on the bigger code example below. Sorry for the big code block, but I don't know how to explain it that exactly...
class IAcceptable
{
public:
// interface; implementors should return map of job-ids (int)
// and a kind of pointer to a method which should be called to
// handle the job.
virtual std::map<int, SOME_KIND_OF_FUNCTION_POINTER> GetJobIds() const = 0;
};
class Class12 : public IAcceptable
{
public:
void Handle_1(){} // method to handle job id 1
void Handle_2(){} // method to handle job id 2
virtual std::map<int, SOME_KIND_OF_FUNCTION_POINTER> GetJobIds() const
{
std::map<int, SOME_KIND_OF_FUNCTION_POINTER> intToMethodMap;
// return map, which says: "I can handle job id 1, by calling Handle_1(), so I give you c12 pointer to this method"
// (same thing for job id 2 and Handle_2())
intToMethodMap.insert(std::pair<int, SOME_KIND_OF_FUNCTION_POINTER>(1, POINTER_TO_Handle_1);
intToMethodMap.insert(std::pair<int, SOME_KIND_OF_FUNCTION_POINTER>(2, POINTER_TO_Handle_2);
return intToMethodMap;
}
};
class Class34 : public IAcceptable
{
void Handle_3(){} // method to handle job id 3
void Handle_4(){} // method to handle job id 4
virtual std::map<int, SOME_KIND_OF_FUNCTION_POINTER> GetJobIds() const
{
std::map<int, SOME_KIND_OF_FUNCTION_POINTER> intToMethodMap;
// return map, which says: "I can handle job id 3, by calling Handle_3(), so I give you c12 pointer to this method"
// (same thing for job id 4 and Handle_4())
intToMethodMap.insert(std::pair<int, SOME_KIND_OF_FUNCTION_POINTER>(3, POINTER_TO_Handle_3);
intToMethodMap.insert(std::pair<int, SOME_KIND_OF_FUNCTION_POINTER>(4, POINTER_TO_Handle_4);
return intToMethodMap;
}
};
class FileReader
{
public:
// register an IAcceptable
// and add its handlers to the local list
void Register(const IAcceptable& acc)
{
m_handlers.insert(acc.GetJobIds());
}
// if some job is to do, search for the job id and call
// the found function
void doSomeJob(int i)
{
std::map<int, SOMEFUNCTION>::iterator specificHandler = m_handlers.find(i);
// call here (specificHandler->second)()
}
private:
std::map<int, SOMEFUNCTION> m_handlers;
};
int main()
{
Class12 c12; // can handle job id 1 and 2
Class34 c34; // can handle job id 3 and 4
FileReader fr;
fr.Register(c12);
fr.Register(c34);
fr.doSomeJob(1); // should lead to this call: c12->Handle_1()
fr.doSomeJob(2); // c12->Handle_2();
fr.doSomeJob(3); // c34->Handle_3();
fr.doSomeJob(4); // c34->Handle_4();
}
Well, maybe the design is my problem and someone can give me a hint how to make it better :)
Here's a complete example:
class IAcceptable;
class DelegateBase
{
public:
virtual void Call() = 0;
};
template <class Class> class Delegate: public DelegateBase
{
public:
typedef void (Class::*Function)();
Delegate(Class* object, Function f): func(f) {}
virtual void Call() { (object->*func)(); }
private:
Class* object;
Function func;
};
class IAcceptable
{
public:
// interface; implementors should return map of job-ids (int)
// and a kind of pointer to a method which should be called to
// handle the job.
virtual std::map<int, DelegateBase*> GetJobIds() = 0;
};
class Class12 : public IAcceptable
{
public:
void Handle_1(){} // method to handle job id 1
void Handle_2(){} // method to handle job id 2
virtual std::map<int, DelegateBase*> GetJobIds()
{
std::map<int, DelegateBase*> intToMethodMap;
// return map, which says: "I can handle job id 1, by calling Handle_1(), so I give you c12 pointer to this method"
// (same thing for job id 2 and Handle_2())
intToMethodMap.insert(std::pair<int, DelegateBase*>(1, new Delegate<Class12>(this, &Class12::Handle_1)));
intToMethodMap.insert(std::pair<int, DelegateBase*>(2, new Delegate<Class12>(this, &Class12::Handle_2)));
return intToMethodMap;
}
};
class Class34 : public IAcceptable
{
void Handle_3(){} // method to handle job id 3
void Handle_4(){} // method to handle job id 4
virtual std::map<int, DelegateBase*> GetJobIds()
{
std::map<int, DelegateBase*> intToMethodMap;
// return map, which says: "I can handle job id 3, by calling Handle_3(), so I give you c12 pointer to this method"
// (same thing for job id 4 and Handle_4())
intToMethodMap.insert(std::pair<int, DelegateBase*>(3, new Delegate<Class34>(this, &Class34::Handle_3)));
intToMethodMap.insert(std::pair<int, DelegateBase*>(4, new Delegate<Class34>(this, &Class34::Handle_4)));
return intToMethodMap;
}
};
class FileReader
{
public:
// register an IAcceptable
// and add its handlers to the local list
void Register(IAcceptable& acc)
{
std::map<int, DelegateBase*> jobIds = acc.GetJobIds();
m_handlers.insert(jobIds.begin(), jobIds.end());
}
// if some job is to do, search for the job id and call
// the found function
void doSomeJob(int i)
{
std::map<int, DelegateBase*>::iterator specificHandler = m_handlers.find(i);
specificHandler->second->Call();
}
private:
std::map<int, DelegateBase*> m_handlers;
};
int _tmain(int argc, _TCHAR* argv[])
{
Class12 c12; // can handle job id 1 and 2
Class34 c34; // can handle job id 3 and 4
FileReader fr;
fr.Register(c12);
fr.Register(c34);
fr.doSomeJob(1); // should lead to this call: c12->Handle_1()
fr.doSomeJob(2); // c12->Handle_2();
fr.doSomeJob(3); // c34->Handle_3();
fr.doSomeJob(4); // c34->Handle_4();
return 0;
}
To call a member function we need an object; so your maps should contain not simply method pointers, but something that can encapsulate a complete call: an object + a method pointer. That something is Delegate here.
To make sure that the method is called correctly even if it's defined in a subclass, we need to store both the derived object and the method pointer type-correctly (no casting). So we make Delegate a template, with the derived class as its parameter.
This means that delegates based on methods of different subclasses are incompatible, and cannot be put into a map. To work around this we introduce a common base class, DelegateBase, and the virtual function Call(). Call() can be called without knowing the exact type of stored object / method, and it will be dispatched to a type-correct implementation. Now we can store DelegateBase* pointers in the map.
Also check out boost::function and boost::bind, they provide a generalization for the above, and I think they could also be used to your purposes.
There are several solutions to this sort of problem.
If you have a class which can handle several different jobs, in separate
functions, the simplest solution is to wrap it, several types, e.g.:
class JobsOneAndTwo
{
public:
void doJobOne();
void doJobTwo();
};
class JobOne : public AbstractJob, JobsOneAndTwo
{
public:
virtual void doJob() { doJobOne(); }
};
class JobTwo : public AbstractJob, JobOneAndTwo
{
public:
virtual void doJob() { doJobTwo(); }
};
If this occurs often in the set of jobs, you can create a template (over
two or moer member function pointers) to generate the individual wrapper
functions.
Alternatively, you can dispatch on a data member of the class:
class JobOneAndTwo : public AbstractJob
{
int myJob;
public:
JobOneAndTwo(int id) : myJob( id ) {}
void JobOne();
void JobTwo();
virtual void doJob()
{
switch ( myJob ) {
case 1:
JobOne();
break;
case 2:
JobTwo();
break;
}
};
In this case, you instantiate the class twice, each time passing a
different argument to the constructor.
In most of the cases I've seen, when one class can handle two jobs, it's
because the two jobs differ only in some parameters; this is really just
a variant on the second solution above, except that you don't switch to
call different member functions, you simply use the parameters (passed
into the constructor) in the basic function.
More generally, don't forget that your concrete job classes can have
data, and their behavior can be modified by such data. And that you can
register multiple instances of a single class, with different data.
So you say that you have many handlers, each of which can handle an arbitrary number of job IDs, and you want to register an arbitrary number of handlers and let all of them which apply handle a given job.
To that end, let every handler implement this interface:
struct Handler
{
virtual bool canHandle(job_id_t id) const = 0;
virtual void doJob(job_it_t id) = 0;
};
To register a handler, simply store a pointer in a container:
std::vector<Handler*> handlers;
Then, if you need to do a job, iterate the container and dispatch:
handleJob(job_it_t id)
{
for (std::vector<Handler*>::iterator it = handlers.begin(), end = handlers.end(); it != end; ++it)
{
if ((*it)->canHandle(id))
(*it)->doJob(id);
}
}
typedef void (IAccaptable::*SOME_KIND_OF_FUNCTION_POINTER)();
...
Register(1, (SOME_KIND_OF_FUNCTION_POINTER)(&Class12::Handle1));
Warning: this C-style cast will only work with single inheritance. (Well, actually the cast would compile just fine with multiple inheritance too, but when calling (derivedObject->*funcPtr)() with a funcPtr that points at a member function of a non-first base class, then it would be called without the derivedObject pointer having been properly adjusted to point at the proper subobject belonging to that base, most probably resulting in a crash.)
A better, but more complicated solution would be to register small caller objects instead of member function pointers. When calling the handler functions, these caller objects could appropriately cast the target object.
class CallerBase
{
public:
virtual void Call(Base* object) = 0;
};
template <class Derived>
struct Caller: public CallerBase
{
public:
typedef void (Derived::*Function)();
Caller(Function f): func(f) {}
virtual void Call(Base* object)
{
Derived* derived = static_cast<Derived*>(object);
(derived->*func)();
}
private:
Function func;
};
Register(1, new Caller<Derived>(&Derived::F));
Then your map would contain CallerBase* pointers, and once you find the proper caller, you'd do caller->Call(object). If object in this call is a Derived*, then it will be implicitly cast to Base*, but the virtual Caller<Derived>::Call() function will cast it back to Derived* before actually calling the method.
Method pointers can be a lot of fun.
I don't want to self promote myself but check out my guide on them I wrote back in school.
http://nicolong.com/code-examples/menu-object-tutorial
Might help a little.
I am learning C++ and I am stuck with a problem. I need a way to use a specific subclass within base class. Does it make sense or I am using a wrong approach? SelectBrand should select the subclass, how can I do it?
Here below my simplified classes:
-----
class Protocol {
public:
Protocol() {};
~Protocol() {};
int openPort();
int readPort(char *buffer);
.....
private:
Protocol (const Protocol&);
};
int Protocol::openPort() {......};
int Protocol::readPort() {.........};
/***********************************************************************************/
class Device{
public:
Device(Protocol& port):_protocol(port){}
~Device();
virtual int getEvent(char *buffer) { return -1; }
int Device::selectBrand();
..............
protected:
Protocol& _protocol;
private:
int brand;
Device(const Device&orig);
};
Device::~Device() {}
int Device::selectBrand() {
......
switch (X)
case 1:
"use subclass Brand_B"
case 2:
"use subclass Brand_B"
.......
}
/***********************************************************************************/
class Brand_A:public Device {
public:
Brand_A(Protocol& port);
~Brand_A();
int getEvent(void *rawData);
private:
Brand_A(const Brand_A&);
};
Brand_A::Brand_A(Protocol& port):Device(port) {}
Brand_A::~Brand_A() {}
int Brand_A::getEvent(void *rawData) {
.... readPort(......);
}
/***********************************************************************************/
class Brand_B:public Device {
public:
Brand_B(Protocol& port);
~Brand_B();
int getEvent(void *rawData);
private:
Brand_B(const Brand_B&);
};
Brand_B::Brand_B(Protocol& port):Device(port) {}
Brand_B::~Brand_B() {}
int Brand_B::getEvent(void *rawData) {
.... readPort(......);
}
/* main **********************************************************/
int main(int argc, char **argv) {
Device *mydev;
char *buffer;
..............
mydev->selectBrand();
..........
mydev->getEvent(buffer);
...........
}
This is not a good idea.
Generally the answer is dynamic_cast, but invoking specific behavior of descendants from a base class is usually a bad design sign.
You can try inverting the class hierarchy and using templates.
I figured I should flesh out the comment I made above. First of all, you can check out the Wikipedia page for more information on the abstract factory pattern. Basically it allows you to access different implementations of an interface, with the implementation used determined at runtime. However, you still don't know which implementation you're getting as that is decided in the factory method that returns the implementation of the interface. As a result, you can only ever use the members in the interface and not a specific implementation. An example that uses your classes above would be something like:
class Device
{
virtual int getEvent(void *rawData) = 0;
}
class BrandA : public Device
{
// define constructors/destructors etc.
int getEvent(void *rawData)
{
// BrandA's implementation for getEvent
}
}
class BrandB : public Device
{
// define constructors/destructors etc.
int getEvent(void *rawData)
{
// BrandB's implementation for getEvent
}
}
class DeviceFactory
{
static Device *CreateDevice(/*any parameters for determining the device?*/)
{
// You probably don't want to randomly determine which implementation you use...
if ((rand() % 2) == 0)
{
return new BrandA();
}
else
{
return new BrandB();
}
}
}
int main()
{
// CreateDevice will decide which type of device we use, however we can only
// explicitly reference the members of the base class (Device).
Device *myDevice = DeviceFactory::CreateDevice();
myDevice->getEvent();
return 0;
}
It looks like you might be trying to implement something like polymorphism when C++ will do that for you. If you define virtual methods in your base class and override them in your sub classes, calls to those methods on a pointer or reference to the base type should result in the sub class' implementation being called.
For example:
class BaseClass
{
virtual void DoSomething()
{
printf("base");
}
};
class SubClass : public BaseClass
{
void DoSomething()
{
printf("sub");
}
};
int main()
{
BaseClass *myBase = new SubClass();
myBase->DoSomething(); // should print "sub" to stdout
return 0;
}
You have to know what derived type (type of subclass) you want to use when you create it so that the instance has the added functionality of the derived type. If you don't, all you get is the functionality of the base class, and you cannot treat it as anything but the base class (or anything further up the inheritance hierarchy if your base class inherits from something).
You may even want to use a member to differentiate between different instances if they're not actually doing anything different. It's hard to tell from the code example exactly what you want to do. Maybe a more specific example of what you're trying to achieve rather than how you're trying to achieve it would help.
please, let me reformulate the problem. I have 1 baseClass and some subclasses; Brand_A....Brand_N
Now, in the main() I don't know in advance which subclass I will use; this selection is demanded to a function in the baseClass which I called selectBrand. What I need is a mechanism to select and use the right subclass based on internal conditions. I want to masquerade to the main() the selected subclass. How to get this?
I implemented and tested this code; it works fine. Is it good design or can be done better?
class BehaviorBase
{
public:
virtual ~BehaviorBase() {}
virtual void DoSomethingOn(Object* obj) {}
};
class Object
{
public:
BehaviorBase* behavior;
void DoSomething();
void ChangeBehavior(int param);
~Object();
}
class BehaviorA: public BehaviorBase
{
void DoSomethingOn(Object* obj)
{
printf("Behavior A\n");
}
};
class BehaviorB: public BehaviorBase
{
string other_data;
void DoSomethingOn(Object* obj)
{
printf("Behavior B\n");
}
};
void Object::DoSomething()
{
behavior->DoSomethingOn(this);
}
Object::~Object()
{
delete behavior;
}
void Object::ChangeBehavior(int param)
{
delete behavior;
switch(param)
{
case 1: behavior = new BehaviorA; break;
case 2: behavior = new BehaviorB; break;
}
}
int main(int argc, char **argv) {
int param=1;
Object *obj;
obj= new Object;
obj->ChangeBehavior(param);
obj->DoSomething();
delete obj;
return(0);
}
Ok, the context is some serialization / deserialization code that will parse a byte stream into an 'object' representation that's easier to work with (and vice-versa).
Here's a simplified example with a base message class and then depending on a 'type' header, some more data/function are present and we must choose the right subclass to instantiate:
class BaseMessage {
public:
enum Type {
MyMessageA = 0x5a,
MyMessageB = 0xa5,
};
BaseMessage(Type type) : mType(type) { }
virtual ~BaseMessage() { }
Type type() const { return mType; }
protected:
Type mType;
virtual void parse(void *data, size_t len);
};
class MyMessageA {
public:
MyMessageA() : BaseMessage(MyMessageA) { }
/* message A specific stuf ... */
protected:
virtual void parse(void *data, size_t len);
};
class MyMessageB {
public:
MyMessageB() : BaseMessage(MyMessageB) { }
/* message B specific stuf ... */
protected:
virtual void parse(void *data, size_t len);
};
In a real examples, there would be hundreds of different message types and possibly several level or hierarchy because some messages share fields/functions with each other.
Now, to parse a byte string, I'm doing something like:
BaseMessage *msg = NULL;
Type type = (Type)data[0];
switch (type) {
case MyMessageA:
msg = new MyMessageA();
break;
case MyMessageB:
msg = new MyMessageB();
break;
default:
/* protocol error */
}
if (msg)
msg->parse(data, len);
But I don't find this huge switch very elegant, and I have the information about which message has which 'type value' twice (once in the constructor, one in this switch)
It's also quite long ...
I'm looking for a better way that would just be better ... How to improve this?
One way of approaching it would be using a map and register some kind of factory function for each message type. This means that you get rid of the switch case and can add and remove messages dynamically.
The code would look something like:
// Create the map (most likely a member in a different class)
std::map<BaseMessage::Type, MessageCreator*> messageMap;
...
// Register some message types
// Note that you can add and remove messages at runtime here
messageMap[BaseMessage::MyMessageA] = new MessageCreatorT<BaseMessageA>();
messageMap[BaseMessage::MyMessageB] = new MessageCreatorT<BaseMessageB>();
...
// Handle a message
std::map<Type, MessageCreator*>::const_iterator it = messageMap.find(msgType);
if(it == messageMap.end()) {
// Unknown message type
beepHang();
}
// Now create the message
BaseMessage* msg = it->second.createMessage(data);
The MessageCreator class would look something like this:
class MessageCreator {
public:
virtual BaseMessage* createMessage(void* data, size_t len) const = 0;
};
template<class T> class MessageCreatorT : public MessageCreator {
public:
BaseMessage* createMessage(void* data, size_t len) const {
T* newMessage = new T();
newMessage.parse(data, len);
return newMessage;
}
};
It's a pretty basic question in fact (as you can imagine, you are definitely not the only one deserializing in C++).
What you are looking for is called Virtual Construction.
C++ does not define Virtual Construction, but it's easy to approximate it using the Prototype Design Pattern or using a Factory method.
I personnally prefer the Factory approach, for the reason that the Prototype one means having some kind of default instance that is replicated and THEN defined... the problem is that not all classes have a meaningful default, and for that matter, a meaningful Default Constructor.
The Factory approach is easy enough.
You need a common base class for the Messages, and another for the Parsers
Each Message has both a Tag and an associated Parser
Let's see some code:
// Framework
class Message
{
public:
virtual ~Message();
};
class Parser
{
public:
virtual ~Parser();
virtual std::auto_ptr<Message> parse(std::istream& serialized) const;
};
// Factory of Messages
class MessageFactory
{
public:
void register(std::string const& tag, Parser const& parser);
std::auto_ptr<Message> build(std::string const& tag, std::istream& serialized) const;
private:
std::map<std::string,Parser const*> m_parsers;
};
And with this framework (admittedly simple), some derived classes:
class MessageA: public Message
{
public:
MessageA(int a, int b);
};
class ParserA: public Parser
{
public:
typedef std::auto_ptr<MessageA> result_type;
virtual result_type parse(std::istream& serialized) const
{
int a = 0, b = 0;
char space = 0;
std::istream >> a >> space >> b;
// Need some error control there
return result_type(new MessageA(a,b));
}
};
And at last, the use:
int main(int argc, char* argv[])
{
// Register the parsers
MessageFactory factory;
factory.register("A", ParserA());
// take a file
// which contains 'A 1 2\n'
std::ifstream file = std::ifstream("file.txt");
std::string tag;
file >> tag;
std::auto_ptr<Message> message = factory.parse(tag, file);
// message now points to an instance of MessageA built by MessageA(1,2)
}
It works, I know for I use it (or a variation).
There are some things to consider:
You may be willing to make MessageFactory a singleton, this then allows it to be called at library load, and thus you can register your parsers by instantiating static variables. This is very handy if you don't want main to have to register every single parser type: locality > less dependencies.
The tags have to be shared. It is not unusual either for the tag to be served by a virtual method of the Message class (called tag).
Like:
class Message
{
public:
virtual ~Message();
virtual const std::string& tag() const = 0;
virtual void serialize(std::ostream& out) const;
};
The logic for serialization has to be shared too, it is not unusual for an object to handle its own serialization/deserialization
Like:
class MessageA: public Message
{
public:
static const std::string& Tag();
virtual const std::string& tag() const;
virtual void serialize(std::ostream& out) const;
MessageA(std::istream& in);
};
template <class M>
class ParserTemplate: public Parser // not really a parser now...
{
public:
virtual std::auto_ptr<M> parse(std::istream& in) const
{
return std::auto_ptr<M>(new M(in));
}
};
What's great with templates is that it never stops to amaze me
class MessageFactory
{
public:
template <class M>
void register()
{
m_parsers[M::Tag()] = new ParserTemplate<M>();
}
};
//skipping to registration
factory.register<MessageA>();
Now isn't it pretty :) ?