我知道这是旧的,但它仍然是我在这个问题上的第一个命中。我就是这样做的。
接口头 foo.h:
#pragma once
#include <memory>
enum class Implementations {Simple, Fancy};
class Foo
{
public:
using Ptr = std::unique_ptr<Foo>;
virtual ~Foo() = default;
virtual void do_it() = 0;
};
Foo::Ptr create_foo(Implementations impl); // factory
是的,我知道“pragma once”严格来说不是标准的,但它对我有用。
请注意,这里没有实现任何内容。没有构造函数:抽象类不能被实例化。您通过工厂获得指向接口的指针。为了使虚函数调用起作用,它们必须通过指针调用。虚拟析构函数是默认的,因为它不需要做任何特殊的事情,除了对实现进行多态。工厂是免费功能。无需尝试使其成为静态成员或类似的东西。这不是java。
接口 foo.cpp:
#include "foo.h"
#include "foo_impl.h"
Foo::Ptr create_foo(Implementations impl)
{
switch (impl)
{
case Implementations::Simple:
return std::make_unique<Simple_foo>();
case Implementations::Fancy:
return std::make_unique<Fancy_foo>();
default:
return nullptr;
}
}
这里实现了工厂。请注意,工厂必须知道实现。这就是我们不内联实现它的原因:如果它是内联的,则接口头必须包含实现头,并且通过它,实现的知识将“泄漏”到调用站点。
实现头文件 foo_impl.h:
#pragma once
#include "foo.h"
class Simple_foo : public Foo
{
void do_it() override;
};
class Fancy_foo : public Foo
{
void do_it() override;
};
没什么特别的,只是重写了接口的虚函数。因为这个例子很简单,所以我将两个实现放在同一个文件中。在实际应用中会有所不同。
实现 foo_impl.cpp:
#include "foo_impl.h"
#include <iostream>
void Simple_foo::do_it()
{
std::cout << "simple foo\n";
}
void Fancy_foo::do_it()
{
std::cout << "fancy foo\n";
}
只需实现功能。
主.cpp:
#include "foo.h"
int main()
{
auto sf = create_foo(Implementations::Simple);
sf->do_it();
auto ff = create_foo(Implementations::Fancy);
ff->do_it();
return 0;
}
通过枚举我们可以选择我们想要的实现。指针的类型是 Foo::Ptr
,是 的别名std::unique_ptr<Foo>
。调用站点根本不知道实现,只有接口。
输出将如预期:
simple foo
fancy foo