有几个C ++类需要使用相同的静态方法和不同的实现

时间:2010-08-29 22:53:31

标签: c++ design-patterns

我需要几个C ++类来使用静态方法“register”,但是寄存器的实现在这些类之间有所不同。

它应该是静态的,因为我的想法是用Lua“注册”所有这些类(当然只有一次)。

显然我不能用静态纯虚函数声明一个接口。你们有什么建议我做的?简单是受欢迎的,但我认为某种模板可以工作。

我希望实现的示例

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;
}

5 个答案:

答案 0 :(得分:6)

根据你如何描述这个问题,我不清楚为什么你甚至需要在类上使用'虚拟静态方法'。这应该是完全合法的。

class SomeClass {
  static void register(void) {
    ...
  }
}

class SomeOtherClass {
  static void register(void) {
    ...
  }
}

int main(int argc, char* argv[]) {
  SomeClass::register();
  SomeOtherClass::register();

  return 0;
}

删除RegisterInterface,我认为你不需要它。

答案 1 :(得分:2)

如果有帮助,你可以接受Hitesh的回答,并添加:

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
    }
};

然后:

int main() {
    luaRegisterManager lrm;
    lrm.registrate<someClass>();
    lrm.registrate<someOtherClass>();
}

更一般地说,如果你想在C ++中引入任何动态多态,那么你需要一个对象,而不仅仅是一个类。所以,也许各种register函数应该返回对象,使用一些公共接口基类registeredClassclassRegistrationInfo,或者沿着那些行返回。

可以提供一个您认为需要动态多态性的示例吗?就我所见,Hitesh的代码与您的一个示例完全匹配,因此该示例不得涵盖您所有预期的用例。如果您编写将使用它的代码,也许您将会清楚如何实现它,或者可能有人可以提供建议。

其他可能有用的东西:

#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";
    }
}

如果您尝试将其拆分为多个编译单元,则此代码存在各种问题。此外,这种事情导致内存泄漏检测器的虚假报告,除非您还编写一些代码以最终撕下所有内容,或使用shared_ptr向量,Boost指针向量等。但是你看到了一般认为一个类可以“注册自己”,并且你需要一个对象来进行虚拟调用。

在C ++中,你通常会尝试避免静态初始化,但是在程序开始时支持某种设置/依赖注入。所以通常你只需列出你关心的所有类(在每个类上调用一个函数),而不是尝试自动执行此操作。

答案 2 :(得分:1)

你的意图是高尚的,但你的解决方案正在向“过度工程化”(除非我错过了一个明显的解决方案)。

以下是一种可能性:您可以使用Virtual Friend function idiom例如,

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;
}

答案 3 :(得分:1)

我知道你已经接受了答案,但我想我还是会写出来的。如果使用静态初始化和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>;

此输出

 A
 B

虽然如果我是你,我不会依赖这个命令。请注意,template class Registerable<X>不必与调用do_registration在同一个翻译单元中,您可以将其与Foo的其余定义一起使用。如果你继承自Registerable<>而你没有为你的类写一个static void Register()函数,你会得到一个(不可否认的可能是神秘的)编译器错误,就像你真的有这样的东西一样“静态虚拟”。 “魔术”只是将类特定函数添加到要调用的列表中,这避免了在静态初始化程序中执行实际注册的几个缺陷。您仍然需要致电do_registration以确保发生任何事情。

答案 4 :(得分:0)

这样怎么样?定义接口类:

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

然后定义处理寄存器的类..

// RegisterFoobar.h
class RegisterFoobar{
    public:
        // Constructors etc...
        IFoobar* fooBar;
        static void RegisterFoobar(IFoobar&  fubar){
             foobar = &fubar;
        }
    private:
        void Raise(void){ foobar->Register(); }
}

现在,然后定义另一个类

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

像这样调用代码:

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

也许我误解了你的要求......