考虑具有两个纯虚拟类的情况,例如X
和Y
。 Y
指定一个纯虚方法,该方法返回指向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预处理器来运行我的代码(尽管更多的异常预处理解决方案是受欢迎的/有趣的)。
有没有办法系统地处理这种情况?
答案 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,你明确地告诉他们:你现在拥有它。