C++ 接口

2025 年 8 月 29 日 | 阅读 8 分钟

在 C++ 中,接口是一个概念性构造,它指定了一组方法,任何声称符合接口的类都必须实现这些方法。它充当一个蓝图,在实现者之间强制执行一致的行为,同时隐藏实际实现的细节。通过这样做,C++ 接口增强了代码的模块化、可维护性和可重用性,与面向对象编程的原则完美契合。

然而,C++ 缺乏一个定义的接口关键字,接口的思想是通过抽象类和纯虚函数来实现的。抽象类有一个或多个纯虚函数,这些函数在基类中指定但未实现。这些纯虚函数充当接口的方法,为任何从抽象基类派生的类设置要求。

语法

它具有以下语法:

实现接口

在 C++ 中,实现接口的类必须重写在抽象基类中声明的所有纯虚函数。这些类为接口方法提供必要的实现,遵循规定的契约。

C++ 接口示例

让我们举一个例子来说明 C++ 中的接口。

示例

编译并运行

输出

Circle Area: 78.5398, Perimeter: 31.4159
Rectangle Area: 24, Perimeter: 20

说明

在这个例子中,我们借助抽象类展示了接口的实现。在这种情况下,我们考虑了一个 Shape 类的例子,它充当接口并提供纯虚函数 getArea() 和 getPerimeter(),这些函数在 Circle 和 Rectangle 类中被重写。这些形状根据它们的大小单独计算它们的面积和周长。在 main() 方法中,我们实例化了这两种类型的对象并打印出面积和周长值。

C++ 接口的特点

C++ 接口有几个特点。其中一些如下

  • 纯虚函数:纯虚接口是一个只包含纯虚函数(在定义中声明为 = 0 的函数)的类,换句话说,纯虚函数在接口声明中没有定义。
  • 它不能被实例化:接口类是抽象的,由于至少有一个纯虚函数,因此不能直接初始化。
  • 通过继承实现:一个类通过接口继承,所有纯虚函数都被重写以实现特定的行为。
  • 虚析构函数:它通常是一个虚析构函数,因为当使用基类指针删除对象时,应该正确地清理其派生对象。
  • 无数据成员:在大多数情况下,接口没有数据成员。这些是为了定义行为,而不是为了保存信息。
  • 支持多态性:多态性由接口运行时支持,它提供方法的动态绑定和灵活的代码。
  • 多接口继承
    C++ 允许一个类通过继承多个抽象类来应用多个接口。

C++ 接口的优势

C++ 接口有几个优势,如下

  • 一致性和契约:接口确保类具有相同的接口和一致的行为。这种类似于契约的安排有助于阻止违反预期功能,这对于确保代码可靠性具有巨大意义。
  • 模块化和关注点分离:接口促进了接口和实现的分离。这种分离增强了代码的模块化,使其更容易处理复杂的系统。
  • 多态性和灵活性:接口有助于支持多态性,不同的类可以通过依赖共享方法和接口方法以一致的方式处理。它允许我们将代码开源,使其具有通用性,并将其与未知实现的变体一起使用。
  • 测试和模拟:接口易于单元测试和模拟,因为我们可以模拟接口实现以允许在单元测试期间测试隔离的部分。它有助于在早期开发阶段发现问题。
  • 代码文档:接口的本质决定了它如何文档化类的行为。通过检查接口方法,开发人员可以深入了解功能,而无需深入研究实现的复杂性。

纯虚函数

在 C++ 中,纯虚函数是基类中指定的一个没有实现的函数,通过在其声明中添加 "= 0" 来表示。它充当派生类必须实现的契约。

语法

它具有以下语法:

  • "virtual":它表示此函数是虚函数,允许多态性。
  • "void":它指定返回类型。
  • "myFunction":它表示函数的名称。
  • "= 0":它表示纯虚函数,这意味着它在基类中没有实现,并且必须在派生类中重写。

C++ 抽象类

在 C++ 中,通过将至少一个函数定义为纯虚函数来抽象一个类。纯虚函数的声明中使用 "= 0",派生类必须提供其实现。

C++ 抽象类示例

让我们看一个 C++ 中的抽象类,它有一个抽象函数 draw()。派生类提供其实现:Rectangle 和 Circle。两个类都有不同的实现。

示例

编译并运行

输出

drawing rectangle...
drawing circle...

说明

这里我们使用纯虚函数来定义抽象类 Shape,它反过来由所有派生类实现,并且所有派生类都继承一个 draw() 方法。然后,Rectangle 和 Circle 重写此函数以提供其适当的绘图行为。在 main() 方法的第 14 行,我们实例化这些派生类并调用它们的 draw() 方法,表明运行时的多态性。

实际用例

C++ 接口应用于实际生活场景。通常会有一个 GUI 框架,它有多种按钮(如简单按钮、切换按钮和单选按钮),但它们具有某种共同行为(如触发点击事件)。框架通过定义按钮行为的接口来实现这一点,这样所有类型的按钮都将具有所需的方法,这些方法将在整个过程中一致地工作。

同样,接口可以概述游戏引擎框架中游戏对象(例如,角色、敌人和物品)的操作。这种抽象使开发人员能够通过编程必要的接口方法来添加具有独特行为的新实体。

使用接口的规则

在 C++ 中使用接口有几个基本规则。其中一些如下

  • 使用抽象类:将接口定义为带有纯虚函数的抽象类。
  • 接口名称前缀:考虑用 'I' 或类似前缀来表示接口的角色。
  • 无成员数据:接口不应包含成员数据(属性)。
  • 公共访问:将接口方法声明为公共,以便外部使用。
  • 显式 virtual 和 override:重写时使用 virtual,并使用 override 表示显式重写。
  • 实现所有方法:任何实现接口的类都必须继承接口的所有方法。
  • 保持专注:接口方法应与主题或目的相关。
  • 文档化接口:文档化接口将如何使用以及其目的。
  • 考虑隔离:不要强迫类使用与它们无关的方法(接口隔离原则)。
  • 稳定的接口:不要对已在使用的接口添加破坏性更改。

结论

总而言之,C++ 接口通常借助抽象类实现。包含至少一个纯虚函数的类。这些使开发人员能够指定一个契约,派生类必须满足该契约,这使得面向对象设计具有允许多态性和松散耦合的可能性。由于接口的正确使用,代码可以更具可维护性、灵活性和可扩展性,尤其是在大型系统和框架中。

C++ 接口 MCQ

1) 关于 C++ 接口的以下哪个说法是正确的?

  1. C++ 有内置的接口关键字
  2. 只有一个类可以实现一个接口
  3. C++ 接口通常是带有纯虚函数的抽象类
  4. 接口不能被继承
 

答案: c) C++ 接口通常是带有纯虚函数的抽象类


2) 为什么开发人员可以选择在 C++ 中使用接口(抽象类)而不是具体基类?

  1. 为了减少编译时间
  2. 为了避免虚函数
  3. 为了对派生类应用契约
  4. 为了防止对象切片
 

答案: c) 为了对派生类应用契约


3) C++ 中的抽象类可以有构造函数吗?

  1. 不可以,接口中不允许有构造函数
  2. 可以,但它们只能通过派生类调用
  3. 可以,并且抽象类可以实例化
  4. 不可以,抽象类中只允许有稳定方法
 

答案: b) 可以,但它们只能通过派生类调用


4) C++ 中的抽象类可以同时拥有纯虚函数和非虚函数吗?

  1. 可以,它可以混合纯虚函数和常规成员函数
  2. 不可以,所有函数都应该是虚函数
  3. 不可以,接口中可能没有实现
  4. 仅当它是模板类时
 

答案: a) 可以,它可以混合纯虚函数和常规成员函数


5) 我们如何使用 C++ 接口实现行为的多重继承?

  1. 通过使用稳定基类
  2. 只使用模板
  3. 在 C++ 中不可能
  4. 通过继承许多抽象类
 

答案: d) 通过继承许多抽象类