接口在C++中是一种很好的做法吗?

Are interfaces a good practice in C++?

本文关键字:很好 一种 C++ 接口      更新时间:2023-10-16

来自Java/python世界,几乎没有C++经验,为了Liskov替换原则和依赖注入,我习惯于使用接口将类的契约与其实现分开。

我不打算讨论 Java 中接口的所有好处,或者为什么引入它们(缺乏多重继承(并且C++不需要(例如,请参阅此处(。 我还发现了如何在C++中拥有等效的Java接口

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

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

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

例如,谷歌测试很容易模拟虚拟方法,但提出了一种模拟非虚拟方法的方法。

我试图弄清楚我的编码习惯是否仍然适用于我的新C++环境,或者我是否应该适应和改变我的范式。

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

我得到了我正在寻找的部分答案(即"是/否与参数"(,我想我应该澄清更多我仍在试图弄清楚的内容

  • 是否有使用类似接口的设计进行依赖注入的替代方法?
  • 反过来说:如果一个人决定采用基于接口的设计,除非速度绝对至关重要,什么时候不想做一个基于纯虚拟方法的界面?

笔记:

  • 我想我试图弄清楚我在界面方面是否思维过于狭隘(因此我的编辑正在寻找替代方案(。
  • 我在 C++ 11 环境中工作

我想说接口在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++,你将用自己的判断来决定你将如何完成你想要的多态行为。如何做到这一点没有单一的正确答案,就像也没有错误的答案一样。抽象基类和模板鸭子类型都是很好的工具,用途略有不同。