関数を宣言しながらクラスの関数をマップします
質問
この主題に関する私の以前の質問に答えられ、私はいくつかのテストをうまく機能させました。クラスのマップ関数
私の質問は、この機能を宣言しながら、名前空間とクラスに関するこの質問で気づいたように、マップに登録できるようにする方法がある場合です。どういうわけか私のクラスをリストに登録してください
名前空間とクラスは、「静的」キーワードを使用してマップに登録するのに適していました。それに伴い、それらの静的インスタンスはメイン()が呼び出される前に構築されます。
クラス関数でどういうわけかそれを行うことはできますか?
クラス宣言内で静的キーワードを使用すると、クラス宣言の外でできるようにメンバーを初期化できないため(上記の2番目のURLの名前空間やクラスと同様)
コンストラクター内のすべてのメンバーをハードコードしてマップに登録できると思いますが、メンバーを宣言している間にそれを行う方法があるかどうかを知りたいと思います。
ありがとうございました、
ジョー
解決
ここであなたの問題は何ですか?
問題は、残念ながら、C ++では、関数がファーストクラスのメンバーとは見なされないことです。
確かに、機能する機能へのポインターはかなりうまく機能しますが、一般的な関数タイプなどはありません。
ただし、これを回避する方法がありますが、最も簡単だと思います Command
パターン。
の中に Command
パターンA関数(操作)は、オブジェクトで抽出されます。引数は、後で再利用するためにオブジェクトに保存されます(たとえば 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();
}
この提案にはまだいくつかの作業が必要です。
- パラメーターを渡すことは、ダウンキャストが必要なため、非常に迷惑です。
- 私は例外の安全性に関心がありませんでしたが、
auto_ptr
またはashared_ptr
より良いでしょうclone
方法... - aの区別
const
そして非const
Fooの議論は紹介するのがそれほど簡単ではありません。
ただし、使用するよりも安全です void*
RTTIの利点があるため、タイプが正しいかどうかを確認するために、マップに機能するポインターを保存するため。
一方、特定のオブジェクトにリンクされたコマンドのコレクションを印刷することは非常に簡単です(オブジェクトごとに1つのマップがある場合)、の効果をエミュレートする方法を見つけることができます virtual
方法など...
しかし、私はあなたが実際に反省を実装しようとしていることを理解してください、そしてそれは簡単ではありません...幸運を!
他のヒント
プリプロセッサを使用して、次のようなコードを許可できます。
#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
あなたが求めているのは、呼ばれる原則です 反射. 。残念ながら、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 ++に靴hornすることは可能かもしれませんが、結果のクラスを書いたり使用したりすることは些細なことではありません。