我需要几个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;
}
答案 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
函数应该返回对象,使用一些公共接口基类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 ++中,你通常会尝试避免静态初始化,但是在程序开始时支持某种设置/依赖注入。所以通常你只需列出你关心的所有类(在每个类上调用一个函数),而不是尝试自动执行此操作。
答案 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...
}
也许我误解了你的要求......