系统地包装纯虚拟类

时间:2014-06-24 19:13:15

标签: c++ c++11 wrapper

考虑具有两个纯虚拟类的情况,例如XYY指定一个纯虚方法,该方法返回指向X实例的智能指针(例如virtual unique_ptr<X> getX() const = 0)。这样做是为了使Y的子类可以返回他们想要的X的任何实现。

但是,这意味着用户必须知道在调用getX()时,他们应该使用unique_ptr<X>的实例(不理想)。通过在类中包装unique_ptr<X>可以很容易地解决这个问题,如下例所示:

#include <iostream> // cout, endl
#include <memory>   // unique_ptr

using namespace std;

////////////////////////////////////////////////////////////////////////////////

struct X {
    virtual void exampleMethod() = 0;
};

struct XCloneable : public X {
    typedef unique_ptr<XCloneable> P;
    virtual P clone() const = 0;
};

class XWrapper : public X {
    XCloneable::P p;

public:
    XWrapper(XCloneable::P p) noexcept : p(move(p)) {}
    XWrapper(const XWrapper &that) noexcept : p(that.p->clone()) {}
    XWrapper &operator=(const XWrapper &that) noexcept {
        p = that.p->clone();
        return *this;
    }
    XWrapper(XWrapper &&that) noexcept : p(move(that.p)) {
    }
    XWrapper &operator=(XWrapper &&that) noexcept {
        p = move(that.p);
        return *this;
    }

    virtual void exampleMethod() { p->exampleMethod(); }
};

////////////////////////////////////////////////////////////////////////////////

struct XX : public XCloneable {
    virtual void exampleMethod() { cout << "XX" << endl; }
    virtual XCloneable::P clone() const { return XCloneable::P(new XX); }
};

////////////////////////////////////////////////////////////////////////////////

struct Y {
    virtual XWrapper getX() = 0;
};

struct YY {
    virtual XWrapper getX() { return XWrapper(XCloneable::P(new XX)); }
};

////////////////////////////////////////////////////////////////////////////////

int main() {
    YY yy;
    auto x = yy.getX();

    x.exampleMethod();

    return 0;
}

但是,这非常冗长,必须为每个类似于X的纯虚拟类编写。我想,系统地自动生成包装器并不太困难,尽管我更喜欢不通过常用的C预处理器来运行我的代码(尽管更多的异常预处理解决方案是受欢迎的/有趣的)。

有没有办法系统地处理这种情况?

1 个答案:

答案 0 :(得分:1)

您所谈论的模式是抽象工厂。我真的不确定为什么你的问题中的大多数代码都存在...这是一个抽象工厂实现的例子,应该做你需要的:

#include <iostream>
#include <memory>

class X
{
public:
    virtual void exampleMethod() = 0;
};

class MyX : public X
{
public:
    void exampleMethod() override
    {
        std::cout << "Calling MyX::exampleMethod()";
    }
};

class XFactory
{
public:
    virtual std::unique_ptr<X> createX() = 0;

    static XFactory* getInstance()
    {
        return m_instance.get();
    }

    static void setInstance(std::unique_ptr<XFactory> instance)
    {
        m_instance = move(instance);
    }

private:
    static std::unique_ptr<XFactory> m_instance;
};

std::unique_ptr<XFactory> XFactory::m_instance = std::unique_ptr<XFactory>();

class MyXFactory : public XFactory
{
public:
    std::unique_ptr<X> createX() override
    {
        return std::unique_ptr<X>(new MyX);
    }
};

int main()
{
    // Call setInstance with different XFactory implementations to get back
    // different implementations of X.
    std::unique_ptr<XFactory> xFactory(new MyXFactory);
    XFactory::setInstance(move(xFactory));

    std::unique_ptr<X> x = XFactory::getInstance()->createX();

    x->exampleMethod();

    return 0;
}

此示例输出:

Calling MyX::exampleMethod()

我根本没有看到你需要一个包装器,尽管只要它延伸MyXFactory::createX()就没有理由你不能从X返回一个。

编辑:

我只是重新阅读了你的问题,为什么调用者不知道他们正在处理unique_ptr?我认为这是理想。通过给他们一个unique_ptr,你明确地告诉他们:你现在拥有它。