关于抽象类:为什么使用C ++接口作为类之间的连接?

Why use a C++ Interface as a connection between classes?

我有一些关于C++接口的问题。

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

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

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

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

1
2
3
4
5
6
7
8
9
class MyAbstractClass {
public:
  virtual ~MyAbstractClass() {}

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

  virtual void Method3() = 0;
};

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

1
2
3
4
5
6
7
class MyInterface {
public:
  virtual ~MyInterface() {}

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


免责声明:如果老师这么说的话,一定要为你的课程使用虚拟界面!以下只是您真正需要使用它们的一个解释。

事实证明,你可以使用一个普通的类使用一个名为模板的C++特性。例如,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/** ...
 *  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的方法,可以用任何类填充它,该方法可以适合上述用例。请注意,记录类型参数的要求很重要。

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

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

你可以分开做

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

这是静态/编译时/参数多态性(请选择)。但是,如果您想在不同类型的网络上使用单个Analyzer(动态/运行时/oo多态性),例如:

1
2
3
4
5
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方法。

1
2
3
4
5
6
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)最好默认为模板+文档(更简单、更灵活、更具性能),然后在需要动态多态性时将其升级到接口。


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

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


But why do I need an interface for that? Couldn't I just use a normal class for that instead a class which is derived from an interface?

因为您通常希望在将来的扩展中保持代码的可修改性,或者添加新的分析器来与您的网络类交互。另外,与底层网络通信的方式可能不同,您需要以灵活透明的方式为分析器处理这些信息。

He made it sound that in order to extract information from another class you need to have a interface-derived class. Is there any benefit from using an interface here?

这不是严格必要的,但好处是,如果项目经理让您执行上面所述的某些东西(不同的分析算法或不同的网络传输),那么在不重写所有代码的情况下,进行这些更改将变得更加容易。

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