ここで説明されているように、友情は継承でも推移的でもありません:継承のあるフレンドクラス。
少し実験した後、このハックを使用してグローバルコンテナをセットアップする方法 (C++03)? 、オブジェクトを作成するための「工場」固有の権利を与える方法を見つけたと思います。
これは簡単で汚いコードです。(ハックを表示するには、一番下に向かってスクロールします。)
class Object {};
class Factory {
public:
// factory is a singleton
// make the constructor, copy constructor and assignment operator private.
static Factory* Instance() {
static Factory instance;
return &instance;
}
public: typedef Object* (*CreateObjectCallback)();
private: typedef std::map<int, CreateObjectCallback> CallbackMap;
public:
// Derived classes should use this to register their "create" methods.
// returns false if registration fails
bool RegisterObject(int Id, CreateObjectCallback CreateFn) {
return callbacks_.insert(CallbackMap::value_type(Id, createFn)).second;
}
// as name suggests, creates object of the given Id type
Object* CreateObject(int Id) {
CallbackMap::const_iterator i = callbacks_.find(Id);
if (i == callbacks_.end()) {
throw std::exception();
}
// Invoke the creation function
return (i->second)();
}
private: CallbackMap callbacks_;
};
class Foo : public Object {
private: Foo() { cout << "foo" << endl; }
private: static Object* CreateFoo() { return new Foo(); }
public:
static void RegisterFoo() {
Factory::Instance()->RegisterObject(0, Foo::CreateFoo);
}
};
class Bar : public Object {
private: Bar() { cout << "bar" << endl; }
private: static Object* CreateBar() { return new Bar(); }
public:
static void RegisterBar() {
Factory::Instance()->RegisterObject(1, Bar::CreateBar);
}
};
// use the comma operator hack to register the create methods
int foodummy = (Foo::RegisterFoo(), 0);
int bardummy = (Bar::RegisterBar(), 0);
int main() {
Factory::Instance()->CreateObject(0); // create foo object
Factory::Instance()->CreateObject(1); // create bar object
}