簡體   English   中英

有幾個C ++類需要使用相同的靜態方法和不同的實現

[英]Several C++ classes need to use the same static method with a different implementation

我需要幾個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;
}

根據你如何描述問題,我不清楚為什么你甚至需要在類上使用“虛擬靜態方法”。 這應該是完全合法的。

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,我認為你不需要它。

如果它有幫助,你可以采取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函數應該返回對象,使用一些公共接口基類registeredClass ,或classRegistrationInfo ,或者沿着那些行。

可以提供一個例子,你覺得你需要動態多態嗎? 就我所見,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 ++中,您通常會嘗試避免靜態初始化,但在程序開始時支持某種設置/依賴注入。 所以通常你只需列出你關心的所有類(在每個類上調用一個函數)而不是自動嘗試這樣做。

你的意圖是高尚的,但你的解決方案是“過度工程”(除非我錯過了一個明顯的解決方案)。

這是一種可能性:您可以使用虛擬朋友功能成語例如,

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

我知道你已經接受了答案,但我想我還是會寫出來的。 如果使用靜態初始化和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才能發生任何事情。

這樣怎么樣? 定義接口類:

// 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...
}

也許我誤解了你的要求......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM