使用C ++接口的最佳方式

时间:2009-07-29 04:31:47

标签: c++ interface

我有一个类似于的接口类:

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 ++”。

7 个答案:

答案 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背景的人使用的新常常比需要的要多。在您的示例中,在堆栈上创建变量就足够了。