C ++用于在另一个类中使用抽象类对象的设计模式

时间:2011-06-13 05:45:35

标签: c++ design-patterns abstract-class

我有一个包含2个纯虚方法的类,另一个类需要使用这个类的对象。我想允许这个类的用户指定应该在其中使用抽象类的哪个派生。 我正在努力弄清楚正确的方法是什么。

struct abstract {
    virtual int fst_func() = 0;
    virtual void sec_func(int) = 0;
};

// store an instance of "abstract".
class user_of_abstract
{
private:
    abstract* m_abstract;

public:
    // Pass a pointer to an "abstract" object. The caller takes care of the memory resource.
    user_of_abstract_base(abstract* a) : m_abstract(a) { }

    // Pase any type, which needs to be derived from "abstract" and create a copy. Free memory in destructor.
    template<class abstract_type>
    user_of_abstract_base(abstract_type const& a) : m_abstract(new abstract_type(a)) { }

    // use the stored member to call fst_func.
    int use_fst_func() {
        return this->m_abstract->fst_func();
    }

    // use the stored member to call sec_func.
    void use_sec_func(int x) {
        this->m_abstract->sec_func(x);
    }
};

// use boost::shared_ptr
class user_of_abstract
{
private:
    boost::shared_ptr<abstract> m_abstract;

public:
    // Pass a pointer to an "abstract" object. The caller takes care of the memory resource.
    user_of_abstract_base(boost::shared_ptr<abstract> a) : m_abstract(a) { }

    // use the stored member to call fst_func.
    int use_fst_func() {
        return this->m_abstract->fst_func();
    }

    // use the stored member to call sec_func.
    void use_sec_func(int x) {
        this->m_abstract->sec_func(x);
    }
};

// pass a pointer of an "abstract" object wherever needed.
struct user_of_abstract
{
    // use the passed pointer to an "abstract" object to call fst_func.
    int use_fst_func(abstract* a) {
        return a->fst_func();
    }

    // use the passed pointer to an "abstract" object to call sec_func.
    void use_sec_func(abstract* a, int x) {
        a->sec_func(x);
    }
};

值得注意的是,sec_func()中的参数“x”必须是fst_func()在同一“抽象”实例上返回的值。

修改 使用boost :: shared_ptr添加了另一种方法,它应该占据最大优势。

3 个答案:

答案 0 :(得分:1)

既然你说第二个函数应该使用第一个函数的输出。我想第一种方法将减少错误的机会。您甚至可以将其修改为以下内容:

int use_fst_func() {
    return x=this->m_abstract->fst_func();
}

void use_sec_func() {
    this->m_abstract->sec_func(x);
}

protected:
   int x;

答案 1 :(得分:1)

我想说将abstract对象传递给用户的构造函数是正确的方法,因为用户的方法依赖于在同一个abstract对象上调用。我甚至会更进一步,使x参数成为用户的内部状态,因为您已经说过,这个值是第一个函数调用返回的值很重要。

更新:如果您担心生命周期,那么您可以使用各种智能指针选项,例如boost。这些应涵盖大多数使用场景。

答案 2 :(得分:0)

你让自己陷入了维修困境。

在您的第一个例子中......

真的不需要模板构造函数。它的编号为

// Parse any type, which needs to be derived from "abstract" and create a copy.

用户已经可以通过自己创建实例并将其传递给第一个构造函数来实现。

另外,有了这个:

// Free memory in destructor.

您明确表示您不知道应该如何使用此类。在编写第一个示例时,您需要决定:使用从外部创建的实例或使用在内部创建的实例。看到一个接口与一个ctor接受一个指针而另一个ctor接受一个引用,这两者基本上都属于同一类型,这很令人困惑。

在我看来,唯一可以接受的方法是使用从外部创建的实例,该实例不是内存管理的从内部创建的实例,将由内存管理,是一个默认的ctor,可以将内部指针初始化为一个合理的值(但这似乎不是这种情况,因为你想复制另一个实例):

template <typename T>
class user_of_abstract
{
    bool m_owner_;
    abstract* m_abstract;

public:

    user_of_abstract_base(abstract* a = NULL)
    : m_owner(a == NULL)
    , m_abstract(m_owner ? new T(): a)
    {
    }

    ~user_of_abstract_base()
    {
        if (m_owner)
        {
            delete m_abstract;
        }
    }
}

你的第二个例子......

优于第一个,因为您没有明确地将内存管理与内存引用混合在一起。您让shared_ptr隐式地执行此操作。非常好,这就是它的用途。

但是,由于您要求use_sec_func必须将use_fst_func的输出作为输入,因此您需要远离维护问题的安全海岸。

例如,如果某个实例上的use_fst_func抛出异常并且稍后在同一个实例上调用use_sec_func会发生什么?

您如何期待重要信息“始终在B之前调用A而且只有一次。并将A结果传递给B.”应该从2年后传播给班级用户吗?

为什么use_sec_func无法拨打use_fst_func

至于你的第三个例子......

当你想要使用它而不是直接调用实例函数时,你能给出一个单独的场景吗?