在声明函数时映射类的函数

时间:2009-11-24 21:44:00

标签: c++ class function map members

我之前关于这个问题的问题得到了解答,我得到了一些很好的测试。 Map functions of a class

现在我的问题是,如果有办法在声明函数时,能够在地图中注册它,就像我在关于命名空间和类的问题中意识到的那样: Somehow register my classes in a list

命名空间和类可以使用“static”关键字在地图中注册,这样,那些静态实例将在调用main()之前构建。

我可以用类功能以某种方式这样做吗? 因为当我在类声明中使用static关键字时,我无法初始化该成员,因为我可以在类声明之外(与上面第二个url中的命名空间和类一样)

我想我可以对构造函数中的所有成员进行硬编码并在地图中注册它们,但我想知道在我宣布成员时是否有办法做到这一点,以便将来更容易

谢谢你,

3 个答案:

答案 0 :(得分:1)

您可以使用预处理器来允许以下代码:

#include <iostream>

#include "Registration.h"

class myclass {
  public:
  myclass() { HANDLE_REGISTRATION(); }

  private:
  static void reg1()  { std::cout << "reg1" << std::endl; }
  static void reg2()  { std::cout << "reg2" << std::endl; }
  static void unreg() { std::cout << "ERROR!" << std::endl; }

  BEGIN_REGISTRATION();
    REGISTER(reg1);
    REGISTER(reg2);
  END_REGISTRATION();
};

int main()
{
  myclass obj;
  obj.callAllRegistered();

  return 0;
}

丑陋的预处理程序黑客隐藏在Registration.h

#ifndef INCLUDED_REGISTRATION_H
#define INCLUDED_REGISTRATION_H

#include <string>
#include <map>

#define BEGIN_REGISTRATION() \
  std::map<std::string, void(*)()> reg; \
  void register_static(const std::string& name, void(*f)()) \
  { \
    reg[name] = f; \
  } \
  void registerAll() {

#define REGISTER(name) register_static(#name, name)

#define HANDLE_REGISTRATION() registerAll()

#define END_REGISTRATION() \
  } \
  public: \
  void callAllRegistered() { \
    std::map<std::string,void(*)()>::const_iterator it; \
    for (it = reg.begin(); it != reg.end(); ++it) \
      it->second(); \
  } \
  private: \
  typedef int unusedblahblahblah___

#endif

答案 1 :(得分:1)

您所寻求的是一项名为Reflection的原则。不幸的是,C / C ++没有提供这种功能,在C ++对象中实现它会非常复杂(如果可能的话)。

如果需要此功能,我建议您查看另一种支持此类元编程功能的语言。在其他一些语言中,做这件事是微不足道的。例如,在Ruby中你可以说:

class Myclass
  def initialize
  end

  def a
  end

  def b
  end
end

x = Myclass.new
x.methods
=> ["inspect", "b", "clone", "taguri", "public_methods", "display", "instance_va
riable_defined?", "equal?", "freeze", "taguri=", "methods", "respond_to?", "dup"
, "instance_variables", "to_yaml_style", "__id__", "method", "eql?", "id", "sing
leton_methods", "send", "taint", "frozen?", "instance_variable_get", "__send__",
"instance_of?", "to_a", "type", "to_yaml_properties", "protected_methods", "obj
ect_id", "instance_eval", "==", "===", "instance_variable_set", "to_yaml", "kind
_of?", "extend", "to_s", "a", "hash", "class", "tainted?", "=~", "private_method
s", "nil?", "untaint", "is_a?"]

这将列出与该对象关联的所有成员函数(在这种情况下,其中许多是自动生成的)。对于实例变量等也可以这样做。许多其他语言提供这些类型的功能。

如果此功能对您正在做的事情至关重要,那么我建议您重新检查您选择的编程语言,因为您似乎希望在比C / C ++通常设计的更高级别上工作。有可能通过使用某种对象/类生成器模式将这类东西塞进C ++中,但编写或使用结果类并不是一件容易的事。

答案 2 :(得分:1)

这里有什么问题?

问题在于,遗憾的是,在C ++函数中不被视为一等成员。

哦,确定有那些功能指针很好用,但是没有通用的函数类型或类似的东西。

但是有一些方法可以解决这个问题,最简单的我认为是Command模式。

Command模式中,函数(操作)在对象中被抽象掉。参数存储在对象中以供以后重用(例如undoredo命令),并且存在一个统一的接口来执行操作本身。

少说话,更多代码:

class Command
{
public:
  virtual ~Command() {}

  virtual Command* clone() const = 0;

  virtual void execute() = 0;
};

简单吗?

class Foo {};

class FooCommand: public Command
{
public:
  void parameters(Foo& self, int a, std::string const& b);

  virtual FooCommand* clone() const;
  virtual void execute();

private:
  Foo* m_self;
  int m_a;
  std::string const* m_b;
};

现在,甜蜜的是我可以简单地将我的命令存储在地图中。

 // registration
 typedef boost::ptr_map<std::string, Command> commands_type;

 commands_type commands;
 commands.insert("foo", FooCommand());

 // get the command
 Foo foo;
 FooCommand* cFoo = dynamic_cast<FooCommand*>(commands["foo"].clone());
 if (cFoo != 0)
 {
   cFoo->parameters(foo, 2, "bar");
   cFoo->execute();
 }

此提案仍需要一些工作。

  • 传递参​​数非常烦人,因为它需要向下投射。
  • 我并不关心异常安全问题,但返回auto_ptrshared_ptrclone方法更好......
  • const和非const Foo参数之间的区别并不容易引入。

然而,使用void*来存储指向函数的指针比使用map更安全,因为你有RTTI的优势来检查类型是否正确。

另一方面,打印链接到特定对象的命令集合现在非常容易(如果每个对象有一个映射),您还可以找到模拟virtual方法等效果的方法。 ..

但我希望你意识到你实际上正在尝试实现反思,这并不容易......祝你好运!