接口在C ++中是一种好习惯吗?

时间:2019-09-19 14:13:42

标签: c++

我来自Java / python世界,很少或没有C ++经验,为了Liskov substitution principle和{{3的缘故,我习惯于使用接口来将类与实现之间的契约分开}}。

我不会讨论Java接口的所有优点,也不会介绍为什么引入接口(缺少多重继承)并且C ++不需要接口(dependency injection)。 我还发现了如何使用see here for example

我的问题更多是关于在C ++环境中这是否是一种好习惯。

据我了解,没有纯虚拟方法就不可能有等效的接口。这意味着将接口引入C ++将在代码中带来一些开销(因为虚拟方法equivalent of a Java interface in C++)。

因此,基于纯虚拟方法的接口是件好事吗?还有其他我不知道的实现Liskov替代原理和依赖注入的方法吗?也许使用模板?

例如,谷歌测试introduce an overhead,但提出了has it easy to mock virtual methods的方法。

我试图弄清楚我的编码习惯在新的C ++环境中是否仍然有用,或者我是否应该适应和更改范例。

[根据答案和评论进行编辑]

我得到了我一直在寻找的答案的一部分(即“是/否,带有参数”),我想我应该进一步阐明我仍在努力找出的问题

  • 是否有使用类似接口的设计进行依赖项注入的替代方法?
  • 回答这个问题:除了速度绝对至关重要时,一个人应该决定进行基于接口的设计吗?什么时候 NOT 不希望基于纯虚方法创建接口? li>

注释:

  • 我想我正在尝试弄清我是否在界面方面思维太狭((因此我的编辑正在寻找替代方法)。
  • 我在C ++ 11环境中工作

1 个答案:

答案 0 :(得分:2)

我想说接口在C ++中仍然是一种好习惯。虚拟方法引入的开销很小,并且您会一次又一次听到,过早的优化是一个大错误。抽象基类是C ++中一个众所周知的,易于理解的概念,从长远来看,比卷积模板元编程更喜欢可读性,通用性的概念可以极大地帮助您。

话虽这么说,我会尽量避免多重继承。随之而来的是一些棘手的问题,这就是为什么Java明确禁止它进行常规继承的原因。一个简单的谷歌搜索可以给你更多的解释。

如果您有多个不相关的类,并且希望在每个类上调用相同名称的方法(例如foo()),则可以使用一个模板化的函数来代替它,而不是使用接口

class A {
  void foo() {
    // do something
  }
};

class B {
  void foo() {
    // do something
  }
};

template <typename T>
void callFoo(const T& object) {
  object.foo();
}

int main() {
  A a;
  B b;
  callFoo(a);
  callFoo(b);

  return 0;
}

即使callFoo()中没有明确的“合同”指出该类型必须支持.foo(),但传递给它的任何对象也必须支持它,否则会出现编译错误。这是在编译时回避类型对象的常用方法,并且是某些情况下接口的替代方法。

最终,随着学习更多的C ++,您将使用自己的判断来决定如何实现所需的多态行为。怎么做都没有一个正确的答案,就像没有错误的答案一样。抽象基类和模板鸭子类型都是很好的工具,它们的用途略有不同。