C++ 中的接口:如何声明而不让自己头疼

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

C++ 中的接口:给厌倦了搜索的人的指南

\n\n

如果你曾经用 Java 或 C# 写过代码,然后转向了 C++,那么你很可能问过自己:"这里的 interface 关键字在哪里?"。剧透:它不存在。在 C++ 中,接口是通过抽象类实现的。这不是一个缺陷,而是一个特性,它提供了令人难以置信的灵活性。

\n\n

在 Stack Overflow 上,问题 "How do you declare an interface in C++?" 获得了数千次浏览。这意味着即使是经验丰富的开发人员有时也会感到困惑。今天,我们将一劳永逸地弄清楚如何在 C++ 中声明接口,让你的代码保持干净,让编译器满意。

\n\n

C++ 中的接口是什么?(剧透:它是抽象类)

\n\n

在经典的 OOP 中,接口是一种契约。实现接口的类必须提供其所有方法的实现。在 C++ 中,这个角色由抽象类扮演——一个包含至少一个纯虚函数(pure virtual function)的类。

\n\n

记住主要规则:

\n
    \n
  • 接口 = 所有方法都是纯虚函数的类。
  • \n
  • 抽象类 = 至少有一个方法是纯虚函数的类(但也可以有带实现的普通方法)。
  • \n
\n\n

对于纯接口,我们使用第一种方案:没有逻辑,只有声明。

\n\n

如何声明纯接口:基本语法

\n\n

以下是一个几何图形接口的最小示例:

\n\n
class IShape {\npublic:\n    virtual double area() const = 0;      // 纯虚函数\n    virtual double perimeter() const = 0; // 另一个纯虚函数\n    virtual ~IShape() {}                  // 虚析构函数——必须要有!\n};
\n\n

注意声明末尾的 = 0。这就是“纯虚”的神奇标记。这样的方法在基类中没有主体(实现)。

\n\n

关键点:

\n
    \n
  • 类名中的前缀 I 是接口的非正式约定(I = Interface)。可以不使用,但这有助于代码阅读。
  • \n
  • 虚析构函数是必须的。如果你通过指向接口的指针删除对象,没有虚析构函数会导致未定义行为(也就是说,程序会崩溃)。
  • \n
  • 所有方法都是 public 的——接口应该可以从外部调用。
  • \n
\n\n

接口的实现:从理论到实践

\n\n

现在,让我们编写一个实现我们接口 IShape 的类。假设它是一个圆:

\n\n
class Circle : public IShape {\nprivate:\n    double radius;\npublic:\n    explicit Circle(double r) : radius(r) {}\n\n    double area() const override {\n        return 3.14159 * radius * radius;\n    }\n\n    double perimeter() const override {\n        return 2 * 3.14159 * radius;\n    }\n};
\n\n

关键字 override(C++11 及更高版本)不是必须的,但强烈建议使用。它强制编译器检查你是否确实重写了基类中的虚方法。方法名拼写错误?编译器会说:“错误!接口中没有这个方法”。

\n\n

多态的实际应用

\n\n

现在最有趣的部分来了——我们可以通过统一的接口处理不同的图形:

\n\n
void printShapeInfo(const IShape& shape) {\n    std::cout << "Area: " << shape.area() << "\\n";\n    std::cout << "Perimeter: " << shape.perimeter() << "\\n";\n}\n\nint main() {\n    Circle c(5.0);\n    printShapeInfo(c); // 可以工作!\n    return 0;\n}
\n\n

函数 printShapeInfo 接受一个对 IShape 的引用。它不在乎传递的是哪个具体对象——圆、正方形还是三角形。只要它们实现了接口,一切都能正常工作。这就是多态

博客

书籍推荐