[英]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.