我有一个类似于的接口类:
class IInterface
{
public:
virtual ~IInterface() {}
virtual methodA() = 0;
virtual methodB() = 0;
};
然后我实现了界面:
class AImplementation : public IInterface
{
// etc... implementation here
}
当我在应用程序中使用接口时,最好创建具体类AImplementation的实例。例如
int main()
{
AImplementation* ai = new AIImplementation();
}
或者最好在接口中放置工厂“创建”成员函数,如下所示:
class IInterface
{
public:
virtual ~IInterface() {}
static std::tr1::shared_ptr<IInterface> create(); // implementation in .cpp
virtual methodA() = 0;
virtual methodB() = 0;
};
然后我就可以在main中使用这样的接口:
int main()
{
std::tr1::shared_ptr<IInterface> test(IInterface::create());
}
第一种选择似乎是常见的做法(不是说它的权利)。但是,第二个选项来自“Effective C ++”。
答案 0 :(得分:9)
使用接口的最常见原因之一是,您可以“针对抽象编程”而不是具体实现。
这样做的最大好处是它允许更改代码的各个部分,同时最大限度地减少剩余代码的更改。
因此,虽然我们不知道您正在构建的完整背景,但我会选择接口/工厂方法。
说到这一点,在较小的应用程序或原型中,我经常从具体的类开始,直到我感觉到界面在哪里/是否需要。接口可以引入一个间接级别,这对于您正在构建的应用程序规模可能不是必需的。
因此,在较小的应用程序中,我发现我实际上并不需要自己的自定义界面。像许多事情一样,你需要权衡特定于你的情况的成本和收益。
答案 1 :(得分:5)
还有一个你没有提到的替代方案:
int main(int argc, char* argv[]) { //... boost::shared_ptr<IInterface> test(new AImplementation); //... return 0; }
换句话说,可以使用智能指针而不使用静态“创建”功能。我更喜欢这种方法,因为“创建”功能只会增加代码膨胀,而智能指针的好处是显而易见的。
答案 2 :(得分:2)
您的问题中有两个不同的问题: 1.如何管理创建对象的存储。 2.如何创建对象。
第1部分很简单 - 您应该使用像std :: tr1 :: shared_ptr这样的智能指针来防止内存泄漏,否则需要花哨的try / catch逻辑。
第2部分更复杂。
你不能只想在main()中编写create() - 你必须编写IInterface :: create(),否则编译器会寻找一个名为create的全局函数,不是你想要的。看起来像使用create()返回的值初始化'std :: tr1 :: shared_ptr test'似乎就像你想做的那样,但这不是C ++编译器的工作方式。
关于在界面上使用工厂方法是否比使用新的AImplementation()更好的方法,它可能对你的情况有所帮助,但要注意投机的复杂性 - 如果你正在写界面使它总是创建一个实现,而不是一个BImplementation或CImplementation,很难看出额外的复杂性会给你带来什么。
答案 3 :(得分:1)
“更好”在什么意义上?
如果您只计划拥有一个具体的课程,那么工厂方法不会给您带来太多帮助。 (但话又说回来,如果你只打算有一个具体的类,你真的需要接口类吗?也许是的,如果你正在使用COM。)在任何情况下,如果你能预见一个小的,固定的限制具体类的数量,然后更简单的实现可能是“更好”的,总的来说。
但是如果可能有许多具体的类,并且如果你不想让基类与它们紧密耦合,那么工厂模式可能会很有用。
是的,这个可以帮助减少耦合 - 如果基类为派生类提供了一些方法来向基类注册自己。这将允许工厂知道存在哪些派生类,以及如何创建它们,而无需编译它们的编译时信息。
答案 4 :(得分:1)
使用第一种方法。第二个选项中的工厂方法必须按具体类实现,这在界面中是不可能的。即,IInterface :: create()并不确切知道您实际希望实例化哪个具体类。
静态方法不能是虚方法,并且在具体类中实现非静态create()方法在这种情况下并没有真正赢得任何东西。
工厂方法肯定是有用的,但这不是正确的用途。
Effective C ++中的哪个项目推荐第二个选项?我没有看到它(虽然我也没有第二本书)。这可能会消除误解。
答案 5 :(得分:0)
我会选择第一个选项,因为它更常见,更容易理解。这完全取决于你,但如果你在商业应用程序上工作,那么我会问我的同行他们使用的是什么。
答案 6 :(得分:0)
我的确有一个非常简单的问题:
您确定要使用指针吗?
这个问题可能看似不合逻辑,但来自Java背景的人使用的新常常比需要的要多。在您的示例中,在堆栈上创建变量就足够了。