29

我希望有一个类层次结构,并且只能在工厂内部从它创建对象。

例子:

class Base
{
    protected:
        Base(){};
        virtual void Init(){};

    friend class Factory;
};

class SomeClass : public Base
{
    public://I want protected here! Now it's possible to call new SomeClass from anywhere!
        SomeClass(){};
        void Init(){};
};

class Factory
{
    public:
        template<class T>
        T* Get()
        {
            T* obj = new T();
            obj->Init();

            return obj;
        }
};

int main()
{
    Factory factory;
    SomeClass *obj = factory.Get<SomeClass>();
}

我的问题是我希望能够仅从 Factory 中创建对象,但我不想friend class Factory在从 Base 派生的每个类中声明。

有没有办法在派生类中传播朋友?有没有其他方法可以实现这种行为?

4

7 回答 7

17

不,这是故意不可能的。

是封装的问题。

假设有一个管理任何密码的类“PswClass”,它与其他类是级联朋友:如果我从 PswClass 继承:

 class Myclass : public PswClass {
     .......
 }

通过这种方式,我也许可以访问私有的字段。

于 2012-12-17T15:11:05.130 回答
4

友谊既不是继承的,也不是传递的,如此处所述:具有继承的朋友类

经过一些实验,并利用了这个 hack如何设置全局容器(C++03)?,我想我已经找到了一种方法,赋予“工厂”创建对象的独特权利。

这是一个快速而肮脏的代码。(向下滚动以查看 hack。)

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
}
于 2012-12-17T15:13:09.547 回答
2

不,没有办法friend从基类继承声明。但是,如果您使用Base构造函数private,则无法在没有Factory帮助的情况下创建派生类的实例。

于 2012-12-17T14:58:12.317 回答
2

正如其他人已经说过的,友谊是不可继承的。

这看起来像是“抽象工厂”模式的一个很好的候选者。

假设从 base 派生的“SomeClass”es 以多态方式使用。声明一个抽象工厂基础,它创建 Base 对象。从基础派生每个具体工厂,覆盖基础创建方法......

有关示例,请参见http://en.wikipedia.org/wiki/Abstract_factory_pattern

于 2012-12-17T15:28:18.137 回答
1

你不能那样做。这样做是为了保护封装。请参阅这篇文章:为什么 C++ 不允许继承友谊?

于 2012-12-17T15:00:48.367 回答
0

为了将来参考, OP 和我之间的聊天产生的另一个想法,它只适用friend于 OP 想要的一次使用。当然,这不是一个通用的解决方案,但在某些情况下它可能很有用。

下面的代码是显示基本思想的最小代码。这需要“集成”到Factory代码的其余部分中。

class Factory;

class Top { // dummy class accessible only to Factory
private:
    Top() {}
friend class Factory;
};

class Base {
public:    
    // force all derived classes to accept a Top* during construction
    Base(Top* top) {}  
};

class One : public Base {
public:    
    One(Top* top) : Base(top) {}
};

class Factory {
    Factory() {
        Top top;  // only Factory can create a Top object
        One one(&top);  // the same pointer could be reused for other objects
    }
};
于 2012-12-17T17:31:18.747 回答
0

这不可能。正如其他人所说,友谊不是遗传的。

另一种方法是保护所有类层次结构构造函数,并将工厂函数/类作为朋友添加到您感兴趣的所有类中。

于 2018-09-03T08:58:19.700 回答