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);
}
Related
I'm reading a lot of questions (and answers) about function pointers, functors and callbacks but I still have a confusion about which is the right tool for me.
Some of them cannot apply to my scenario because it seems my compiler avr-gcc v5.4.0 does not have C++ standard library (i.e. std::function is not available).
This is my base class:
class Debouncer
{
public:
typedef uint8_t (Debouncer::*debouncer_raw_t) (void);
Debouncer() {}
void setRawFunction(Debouncer::debouncer_raw_t callback) { _raw = callback; }
private:
debouncer_raw_t _raw;
void anotherFunction()
{
uint8_t value = _raw();
// do something
}
}
In my other classes I have:
class Inputs
{
public:
Inputs()
{
_deb.setRawFunction(myRaw);
}
private:
Debouncer _deb;
uint8_t myRaw()
{
return something;
}
}
Of course this won't compile because myRaw is not static.
Anyway, I'm going to try to avoid this because it would break the existing code.
If I'm not wrong, a lot of questions seem to ask the other way around.
Instead I just want to pass the pointer of my member function to my Debouncer class, so it can call _raw() when it needs to.
Here I found this advise to avoid std:: library:
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
void userCode(Fred& fred, FredMemFn p) // Use a typedef for pointer-to-member types
{
int ans = CALL_MEMBER_FN(fred,p)('x', 3.14);
// Would normally be: int ans = (fred.*p)('x', 3.14);
// ...
}
But it seems the other way around. Here the class Fred is my Debouncer.
I don't want to call the Debouncer member, but member of the caller class (i.e. Input::myRaw()).
Would you please help me to understand which is the right tool to achieve such a simple task?
Making a member function virtual is a relatively low-overhead way to have a single pointer (to an object) refer to both the object's data and the correct member function.
class InputsBase
{
// All classes that implement myRaw() should inherit from this class
public:
virtual uint8_t myRaw() = 0;
};
class Inputs : public InputsBase
{
public:
Inputs()
{
_deb.setRawFunction(this);
}
private:
Debouncer _deb;
virtual uint8_t myRaw()
{
return something;
}
}
Your Debouncer can then simply store a pointer to the object in question.
class Debouncer
{
public:
typedef InputsBase* debouncer_raw_t;
Debouncer() {}
void setRawFunction(debouncer_raw_t callback) { _raw = callback; }
private:
debouncer_raw_t _raw;
void anotherFunction()
{
uint8_t value = _raw->myRaw();
// do something
}
}
If you know (or require) each of the classes using Debouncer have a public myRaw() function (or better operator(), or actually anything else), the problem is simpler:
template <typename T>
class Debouncer
{
public:
Debouncer (T* t): _t(t) {}
void anotherFunction()
{
uint8_t value = _t->myRaw();
std::cout << static_cast<int>(value);
}
private:
T* _t;
};
class Inputs
{
public:
Inputs() : _deb(this)
{
// beware, if Debouncer uses its parameter in constructor (like call a method),
// you cannot use initializer list
}
uint8_t myRaw()
{
return 13;
}
void foo()
{
_deb.anotherFunction();
}
private:
Debouncer<Inputs> _deb;
};
int main()
{
Inputs i;
i.foo();
}
This would be preferred solution in C++. See for example standard library <algorithm> - any function taking a predicate or some other callable expects to call it with operator() rathen than having to deal with pointers-to-member-function.
If you don't know what function should be called and you really cannot impose any requirement on the classes, you need to store both a pointer (or reference) to the class and a pointer to the member function. Note that you cannot connect pointers to member functions of different classes, so we need templates once again:
template <typename T, typename Func>
class Debouncer
{
public:
Debouncer (T* t, Func f): _t(t), _f(f) {}
void anotherFunction()
{
uint8_t value = (_t->*_f)(); //I get it now why isocpp asks to use macro here, the syntax is horrible
std::cout << static_cast<int>(value);
}
private:
T* _t;
Func _f;
};
class Inputs
{
public:
Inputs() : _deb(this, &Inputs::myRaw)
{
// beware, if Debouncer uses its parameter in constructor (like call a method),
// you cannot use initializer list
}
uint8_t myRaw()
{
return 13;
}
void foo()
{
_deb.anotherFunction();
}
private:
Debouncer<Inputs, decltype(&Inputs::myRaw)> _deb; //decltype is C++11, you could also declare type like you did in your question
};
int main()
{
Inputs i;
i.foo();
}
I have a class named MyClass that is subscribed by another class. When some events happen, MyClass should notify subscribers.
I'm trying to use template for the subscriber's type. Because I don't want to let others(who are in charge of subscriber class) need to care about modifying MyClass for subscribing.
So I've written codes below,
class MyClass {
public:
template<typename T>
void subscribeEvents(const T &controller)
{
m_subscriber = static_cast<T*>(m_subscriber);
m_subscriber = &controller;
}
void notifyPositionChanged(const long &position) const {
(m_subscriber)->onPositionChanged(position);
}
private:
void m_subscriber; // will be changed to array or something else
}
Actually the controller object has a method namedonPositionChanged.
But as you know, it's not compiled for this line.
(m_subscriber)->onPositionChanged(position);
Now I understand why it's an error, but the problem is that I don't know how to modify codes or change my design. Please let me know what I'm missing and misunderstanding. Thanks in advance.
You dont need to use template for this. Just use a base class for your subscribers. And MyClass operate on your base class
class ISubscribe {
public:
virtual void onPositionChanged(const long &position) = 0;
};
class MyClass {
public:
void subscribeEvents(ISubscribe *controller)
{
m_subscriber = controller;
}
void notifyPositionChanged(const long &position) const {
(m_subscriber)->onPositionChanged(position);
}
private:
ISubscribe *m_subscriber; // will be changed to array or something else
};
class SampleSubscriber : public ISubscribe {
public :
void onPositionChanged(const long &position) override{
...
}
};
void main() {
SampleSubscriber s;
MyClass m;
m.subscribeEvents(&s);
....
}
You need to define a common interface to all your subscribers, then use this interface as m_subscriber's type. Savagely casting whatever parameter you receive to a defined type will lead only to undefined behaviors.
Use std::function:
class MyClass {
public:
template<typename CALLBACK>
void subscribeEvents(CALLBACK &&controller)
{
m_subscriber = std::forward<CALLBACK>(controller);
}
void notifyPositionChanged(const long &position) const
{
if (m_subscriber)
m_subscriber(position);
}
private:
std::function<void(const long&)> m_subscriber;
}
This gives the subscriber full freedom of what it wants to subscribe. For example:
there.subscribeEvents([this](const long &pos) { handlePosChange(pos); }
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.
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);
}
I need several C++ classes to have a static method "register", however the implementation of register varies between those classes.
It should be static because my idea is to "register" all those classes with Lua (only once of course).
Obviously I can't declare an interface with a static pure virtual function. What do you guys suggest me to do ? Simplicity is welcome, but I think some kind of template could work.
Example of what I would like to achieve
class registerInterface
{
public:
static virtual void register() = 0; //obviously illegal
};
class someClass: public registerInterface
{
static virtual void register()
{
//I register myself with Lua
}
}
class someOtherClass: public registerInterface
{
static virtual void register()
{
//I register myself with Lua in a different way
}
}
int main()
{
someClass::register();
someOtherClass::register();
return 0;
}
Based on how you've described the problem, it's unclear to me why you even need the 'virtual static method' on the classes. This should be perfectly legal.
class SomeClass {
static void register(void) {
...
}
}
class SomeOtherClass {
static void register(void) {
...
}
}
int main(int argc, char* argv[]) {
SomeClass::register();
SomeOtherClass::register();
return 0;
}
Drop the RegisterInterface, I don't think you need it.
If it helps, you could take Hitesh's answer, and add:
struct luaRegisterManager {
template <typename T>
void registrate() {
T::registrate();
// do something else to record the fact that we've registered -
// perhaps "registrate" should be returning some object to help with that
}
};
Then:
int main() {
luaRegisterManager lrm;
lrm.registrate<someClass>();
lrm.registrate<someOtherClass>();
}
More generally, if you want to introduce any dynamic polymorphism in C++, then you need an object, not just a class. So again, perhaps the various register functions should be returning objects, with some common interface base class registeredClass, or classRegistrationInfo, or something along those lines.
Could provide an example of what you feel it is that you need dynamic polymorphism for? Hitesh's code precisely matches your one example, as far as I can see, so that example must not cover all of your anticipated use cases. If you write the code that would be using it, perhaps it will become clear to you how to implement it, or perhaps someone can advise.
Something else that might help:
#include <iostream>
#include <string>
#include <vector>
struct Registered {
virtual std::string name() = 0;
virtual ~Registered() {}
Registered() {
all.push_back(this);
}
static std::vector<Registered*> all;
};
std::vector<Registered*> Registered::all;
typedef std::vector<Registered*>::iterator Iter;
template <typename T>
struct RegisteredT : Registered {
std::string n;
RegisteredT(const std::string &name) : n(name) { T::registrate(); }
std::string name() { return n; }
// other functions here could be implemented in terms of calls to static
// functions of T.
};
struct someClass {
static Registered *r;
static void registrate() { std::cout << "registering someClass\n"; }
};
Registered *someClass::r = new RegisteredT<someClass>("someClass");
struct someOtherClass {
static Registered *r;
static void registrate() { std::cout << "registering someOtherClass\n"; }
};
Registered *someOtherClass::r = new RegisteredT<someOtherClass>("someOtherClass");
int main() {
for (Iter it = Registered::all.begin(); it < Registered::all.end(); ++it) {
std::cout << (*it)->name() << "\n";
}
}
There are all sorts of problems with this code if you try to split it across multiple compilation units. Furthermore, this kind of thing leads to spurious reports from memory leak detectors unless you also write some code to tear everything down at the end, or use a vector of shared_ptr, Boost pointer vector, etc. But you see the general idea that a class can "register itself", and that you need an object to make virtual calls.
In C++ you usually try to avoid static initialisation, though, in favour of some sort of setup / dependency injection at the start of your program. So normally you would just list all the classes you care about (calling a function on each one) rather than try to do this automatically.
Your intentions are noble, but your solution is inkling towards "overengineering" (unless I am missing an obvious solution).
Here is one possibility: You can use the Virtual Friend function idiom For example,
class RegisterInterface{
friend void register(RegisterInterface* x){x->do_real_register();}
protected:
virtual void do_real_register();
}
class Foo : public RegisterInterface{
protected:
virtual void do_real_register(){}
};
class Bar : public RegisterInterface{
protected:
virtual void do_real_register(){}
};
int main(int argc, char* argv[]) {
BOOST_FOREACH(RegisterInterface* ri, registered_interfaces)
{
register(ri);
}
return 0;
}
I know you've already accepted an answer, but I figured I would write this up anyway. You can have self-registering classes if you use some static initialization and the CRTP:
#include <vector>
#include <iostream>
using namespace std;
class RegisterableRoot // Holds the list of functions to call, doesn't actually need
// need to be a class, could just be a collection of globals
{
public:
typedef void (*registration_func)();
protected:
static std::vector<registration_func> s_registery;
public:
static void do_registration()
{
for(int i = 0; i < s_registery.size(); ++i)
s_registery[i]();
}
static bool add_func(registration_func func) // returns something so we can use it in
// in an initializer
{
s_registery.push_back(func);
return true;
}
};
template<typename RegisterableType> // Doesn't really need to inherit from
class Registerable : public RegisterableRoot // RegisterableRoot
{
protected:
static const bool s_effect;
};
class A : public Registerable<A> // Honestly, neither does A need to inherit from
// Registerable<T>
{
public:
static void Register()
{
cout << "A" << endl;
}
};
class B : public Registerable<B>
{
public:
static void Register()
{
cout << "B" << endl;
}
};
int main()
{
RegisterableRoot::do_registration();
return 0;
}
std::vector<RegisterableRoot::registration_func> RegisterableRoot::s_registery;
template <typename RegisterableType> // This is the "cute" part, we initialize the
// static s_effect so we build the list "magically"
const bool Registerable<RegisterableType>::s_effect = add_func(&RegisterableType::Register);
template class Registerable<A>; // Explicitly instantiate the template
// causes the equivalent of
// s_registery.push_back(&A::Register) to
// be executed
template class Registerable<B>;
This outputs
A
B
although I wouldn't rely on this order if I were you. Note that the template class Registerable<X> need not be in the same translation unit as the call to do_registration, you can put it with the rest of your definition of Foo. If you inherit from Registerable<> and you don't write a static void Register() function for your class you'll get a (admittedly probably cryptic) compiler error much like you might expect if there really was such a thing as "static virtuals". The "magic" merely adds the class specific function to the list to be called, this avoids several of the pitfalls of doing the actual registration in a static initializer. You still have to call do_registration for anything to happen.
How about this way? Define an interface class:
// IFoobar.h
class IFoobar{
public:
virtual void Register(void) = 0;
}
Then define the class that handles the register..
// RegisterFoobar.h
class RegisterFoobar{
public:
// Constructors etc...
IFoobar* fooBar;
static void RegisterFoobar(IFoobar& fubar){
foobar = &fubar;
}
private:
void Raise(void){ foobar->Register(); }
}
Now, then define another class like this
// MyFuBar.h
class MyFuBar : IFoobar{
public:
// Constructors etc...
void Register(void);
private:
RegisterFoobar* _regFoobar;
}
Call the code like this:
//MyFuBar.cpp
MyFuBar::MyFuBar(){
_regFoobar = new Foobar();
_regFoobar->RegisterFoobar(this);
}
void MyFuBar::Register(void){
// Raised here...
}
Maybe I have misunderstood your requirements...