0

我之前关于这个主题的问题得到了回答,我得到了一些很好的测试。 类的映射函数

我现在的问题是,如果有办法在声明函数时能够在映射中注册它,就像我在这个关于命名空间和类的问题中所意识到的那样: 以某种方式在列表中注册我的类

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

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

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

谢谢你,

4

3 回答 3

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
于 2009-11-24T22:38:38.650 回答
1

您正在寻求的是一个称为反射的原则。不幸的是,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++ 中,但编写或使用生成的类并非易事。

于 2009-11-24T22:40:27.607 回答
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_ptr或一个shared_ptr对于该方法会更好clone......
  • consta和非Foo 参数之间的区别const并不容易介绍。

但是,它比使用 avoid*存储指向函数的指针更安全,因为您具有 RTTI 的优势来检查类型是否正确。

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

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

于 2009-11-25T13:00:15.683 回答