【问题标题】:Why use a C++ Interface as a connection between classes?为什么使用 C++ 接口作为类之间的连接?
【发布时间】:2018-07-04 21:18:09
【问题描述】:

我对 C++ 中的接口有一些疑问。

据我了解,如果您想使用基类来处理您已经想到的某些任务,并且为此声明了一些方法(但没有定义),则可以使用它们。但是每个派生类都需要为它们的特定目的实现这些方法,因此您可以将它们创建为抽象方法。 抽象类和接口之间的唯一区别是,抽象类至少有一个纯虚方法,而且一些“普通”方法和接口只有纯虚方法。对吗?

我的教授将接口描述为两个类相互通信的一种方式。例如。一个接口用于网络类,一个接口用于分析来自该网络的信息的分析器类。但是为什么我需要一个接口呢?我不能只使用普通类而不是从接口派生的类吗?他说,为了从另一个类中提取信息,您需要有一个接口派生类。在这里使用接口有什么好处吗?

我希望我的问题很清楚,英语不是我的第一语言。

编辑: 抽象类:(1/3的方法是纯虚的)

class MyAbstractClass {
public:
  virtual ~MyAbstractClass() {}

  virtual void Method1();
  virtual void Method2();

  virtual void Method3() = 0;
};

接口:(所有方法都是纯虚的)

class MyInterface {
public:
  virtual ~MyInterface() {}

  virtual void Method1() = 0;
  virtual void Method2() = 0;
};

【问题讨论】:

  • 一个定义良好的接口通常很不错,这样您就可以透明地更改实现细节。尽管您不需要使用抽象类甚至继承。例如,标准容器通过提供类似的成员函数就拥有一个没有继承的统一接口,这使得它们大多可以互换。
  • 请注意,“接口”是一个在编程世界中具有大量含义的词。仔细检查您使用的是同一个。
  • @manni66 - 虽然 C++ 中没有语言构造“命名”接口,但纯虚拟类是完全等价的。
  • 不要将 Java 术语“interface”与英文单词“interface”混淆。
  • 另一种语言注释:不要将作为接口(或“抽象类”)与拥有暴露 i> 一个界面。

标签: c++ abstract-class


【解决方案1】:

免责声明:如果讲师这么说,绝对要为您正在学习的课程使用虚拟界面!以下只是您真正需要使用它们的说明。

事实证明,您可以使用称为模板的 C++ 功能使用常规类。例如,

/** ... 
 *  Network must have the following method: 
 *  size_t readsome(char* buffer_out, size_t buffer_size) */
template<typename Network>
class Analyzer {
public:
  Analyzer(/* constructor arguments */);
  void analyze(Network& network) {
    char[50] buffer;
    const size_t read = network.readsome(&buffer, 50);
    /* ... */
  }
  /* I dunno maybe a view_log function should go here. */
private:
  /* ... */
};

这里,Network 是一个类型参数。你可以用任何类填充它,只要它有一个名为 readsome 的方法,它可以适合上述用例。请注意,记录类型参数的要求很重要。

现在您可以执行以下操作:

CoolNetwork cool_network(/* ... */);
Analyzer<CoolNetwork> analyzer(/* ... */);
while (cool_network.is_open()) { analyzer.analyze(cool_network); }

你可以单独做

CoolerNetwork cooler_network(/* ... */);
Analyzer<CoolerNetwork> analyzer(/* ... */);
while (cooler_network.is_open()) { analyzer.analyze(cooler_network); }

这是静态/编译时/参数多态性(任君选择)。但是,如果您想在不同类型的网络(动态/运行时/OO 多态性)上使用 single Analyzer,例如以下

CoolNetwork cool_network(/* ... */);
CoolerNetwork cooler_network(/* ... */);
Analyzer<Network> analyzer(/* ... */);
while (cool_network.is_open()) { analyzer.analyze(cool_network); }
while (cooler_network.is_open()) { analyzer.analyze(cooler_network); }

那么你需要一个名为Network 的接口类,并带有一个虚拟的readsome 方法。

class Network {
public:
  virtual size_t readsome(char* buffer_out, size_t buffer_size) = 0;
  //is_open doesn't have to be in the interface to make the above
  //snippet compile, but it would probably belong here
};

显然你应该做适合该类的事情,但一般 (IMO) 最好默认为模板+文档(更简单、更灵活、更高效),然后在需要时将其添加到接口 动态 多态性。

【讨论】:

  • IMO 没关系,如果接口表示为 dynamicstatic 多态性。重要的一点是代码基于某些合同工作。
【解决方案2】:

但是为什么我需要一个接口呢?我不能只使用一个普通的类来代替从接口派生的类吗?

因为您通常希望保持代码可修改以供将来扩展或添加新的分析器以与您的网络类交互。
此外,与底层网络通信可能有不同的方式,您需要以灵活和透明的方式对分析器进行处理。

他说,为了从另一个类中提取信息,您需要有一个接口派生类。在这里使用接口有什么好处吗?

这不是绝对必要的,但好处是,如果您的项目经理帮助您实现我上面所说的某些东西(不同的分析算法或不同的网络传输),那么进行这些更改将变得更容易,而无需重写所有代码。

可以在抽象基类中提供不变部分,并在继承类中扩展具体用例。

【讨论】:

  • 谢谢,这真的很有帮助。我想我也低估了这些接口的大小。当你有很多方法要实现时,从接口派生另一个类是有意义的。
  • @jwBerlin 接口通常只代表一小组逻辑相关的函数(经验法则是 3-5)。实现类可以继承多个接口,但使用该接口的另一个类不需要查看实现类的所有功能。
【解决方案3】:

假设您正在编写分析代码,但您的一位同事正在编写网络代码。你可以给你的同事一个接口,然后说‘我不在乎你做什么,只要你写一些遵循那个接口的代码,然后我的代码就能分析它。

但你是对的,你不必使用接口,但有时它们是划分责任的有用方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-08
    • 2013-02-14
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-04
    相关资源
    最近更新 更多