Several C ++ classes should use the same static method with a different implementation

I need some C ++ classes to have a static "register" method, however the implementation of the register varies between these classes.

It should be static, because my idea is to "register" all these classes with Lua (only once, of course).

Obviously, I cannot declare an interface with a static pure virtual function. What are you suggesting me to do? Simplicity is welcome, but I think some kind of template might work.

An 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; } 
+4
source share
5 answers

Based on how you described the problem, I don’t understand why you even need a “virtual static method” for classes. This should be completely 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 RegisterInterface, I don't think you need it.

+6
source

If this helps, you can take a Hitesh 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 ++, you need an object, not just a class. Thus, it is possible that various register functions should return objects with some common base class of the registeredClass or classRegistrationInfo or something in this direction.

Could it be an example of what you consider necessary for dynamic polymorphism? As I can see, the Hitesh code exactly matches your example, so this example should not cover all your expected use cases. If you write a code that will use it, it may become clear to you how to implement it, or 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 kinds of problems with this code if you try to split it into several compilation units. In addition, such things lead to false messages from memory leak detectors if you also do not write any code to tear everything at the end or use the shared_ptr vector, acceleration 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 initialization, although in favor of some kind of installation installation / dependency at the beginning of your program. Therefore, usually you simply list all the classes that interest you (by calling a function on each of them), rather than trying to do it automatically.

+2
source

Your intentions are noble, but your decision implies "overdevelopment" (unless I have an obvious solution).

Here is one of the possibilities: you can use the idiom functions of a virtual friend. 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; } 
+1
source

I know that you have already accepted the answer, but I decided that I would write it anyway. You may have self-registration classes if you use static initialization and 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>; 

Displays

  A B 

although I would not rely on this order if I were you. Note that the template class Registerable<X> does not have to be in the same translation unit as the do_registration call, you can put it in the rest of your Foo definition. If you inherit from Registerable<> and you don't write the static void Register() function for your class, you will get a (possibly cryptic) compiler error, as you would expect if such a thing as “static virtuals” really existed, "Magic" simply adds a class function to the list that will be called, this avoids some errors associated with the actual registration in the static initializer. You should still call do_registration for anything.

+1
source

How about this? Define the interface class:

 // IFoobar.h class IFoobar{ public: virtual void Register(void) = 0; } 

Then define the class that processes 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 define another class like this

 // MyFuBar.h class MyFuBar : IFoobar{ public: // Constructors etc... void Register(void); private: RegisterFoobar* _regFoobar; } 

Call the code as follows:

 //MyFuBar.cpp MyFuBar::MyFuBar(){ _regFoobar = new Foobar(); _regFoobar->RegisterFoobar(this); } void MyFuBar::Register(void){ // Raised here... } 

Perhaps I misunderstood your requirements ...

0
source

All Articles