0

この件に関する以前の質問に回答があり、いくつかのテストがうまく機能しました。 クラスのマップ関数

私の質問は、名前空間とクラスに関するこの質問で気付いたように、関数を宣言している間にそれをマップに登録できる方法があるかどうかです: どういうわけかクラスをリストに登録する

名前空間とクラスは、「static」キーワードを使用してマップに登録しても問題ありませんでした。これにより、これらの静的インスタンスは main() が呼び出される前に構築されます。

クラス関数で何とかできますか?
クラス宣言内で static キーワードを使用すると、クラス宣言の外でできるようにメンバーを初期化できないためです(上記の2番目の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、関数 (操作) がオブジェクトに抽象化されます。引数は、後で再利用するためにオブジェクトに格納され (たとえばundo、またはredoコマンド)、操作自体を実行するための統一されたインターフェイスが存在します。

話が減り、コードが増えます:

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

この提案にはまだいくつかの作業が必要です。

  • パラメーターを渡すのは、ダウン キャストが必要なため、非常に面倒です。
  • 例外の安全性については気にしませんでしたが、メソッドには anauto_ptrまたは aを返すshared_ptr方が良いでしょうclone...
  • constFoo 引数と非Foo 引数の違いconstを導入するのはそれほど簡単ではありません。

void*ただし、型が正しいかどうかを確認する RTTI の利点があるため、関数へのポインターをマップに格納するためにa を使用するよりも安全です。

一方、特定のオブジェクトにリンクされたコマンドのコレクションを印刷することは非常に簡単になりました (オブジェクトごとに 1 つのマップがある場合)。virtualメソッドなどの効果をエミュレートする方法を見つけることもできます...

しかし、実際にはリフレクションを実装しようとしていること、そしてそれは簡単ではないことを理解していただければ幸いです...頑張ってください!

于 2009-11-25T13:00:15.683 に答える