C ++中的抽象类与接口[重复]

Posted

技术标签:

【中文标题】C ++中的抽象类与接口[重复]【英文标题】:Abstract Class vs Interface in C++ [duplicate] 【发布时间】:2012-10-03 00:22:56 【问题描述】:

可能重复:How do you declare an interface in C++?

这是一个关于 C++ 的一般问题。如您所知,与 Java 和 C# 不同,C++ 中的 interfaceabstract class 没有明显区别。什么时候在 C++ 中使用 interface 而不是 abstract class 更可取?可以举一些例子吗?

【问题讨论】:

由于没有明确的区别,您需要定义 you 在 C++ 中“接口”的含义。 (如果没有明确的区别,那么偏爱一个比另一个没有任何意义。) 正如你所说,没有区别,所以除非你定义接口的含义以及它与抽象类的区别,否则这个问题是没有意义的。 @juanchopanza:+1 对您的评论。我自己说得再好不过了。 C++语言没有接口,只能通过抽象类来模拟。 虽然这个问题的措辞当然可以更好,但这样做需要提问者已经知道答案。如此频繁地看到聪明的驴狗堆积在我身上,这让我很恼火。 @Fatma:在寻找何时或如何需要明确原因的答案之前。 “接口”体现了客户端和实现之间的合同的概念。 “抽象类”包含您希望在接口的多个实现之间共享的代码。虽然接口隐含在抽象类方法中,但有时单独指定合同很有用。 【参考方案1】:

我假设 interface 是指只有 纯虚拟 方法(即没有任何代码)的 C++ 类,而不是 抽象类你的意思是一个 C++ 类,它具有可以被覆盖的虚拟方法和一些代码,但至少有一个纯虚拟方法,这使得该类不可实例化。 例如:

class MyInterface

public:
  // Empty virtual destructor for proper cleanup
  virtual ~MyInterface() 

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


class MyAbstractClass

public:
  virtual ~MyAbstractClass();

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

  virtual void Method4() = 0; // make MyAbstractClass not instantiable
;

在 Windows 编程中,接口COM 的基础。事实上,COM 组件只导出接口(即指向 v-tables 的指针,即指向函数指针集的指针)。这有助于定义一个 ABI(应用程序二进制接口),它可以让例如在 C++ 中构建 COM 组件并在 Visual Basic 中使用,或者在 C 中构建 COM 组件并在 C++ 中使用,或者在 Visual C++ 版本 X 中构建 COM 组件并在 Visual C++ 版本 Y 中使用。 换句话说,通过接口,您可以在客户端代码和服务器代码之间实现高度解耦。

此外,当您想要使用 C++ 面向对象的接口(而不是纯 C DLL)构建 DLL 时,如 this article 中所述,最好导出 interfaces(“成熟的方法") 而不是 C++ 类(这基本上是 COM 所做的,但没有 COM 基础结构的负担)。

如果我想定义一组可以用来编程组件的规则,而不指定具体的特定行为,我会使用 接口。实现这个接口的类会自己提供一些具体的行为。

相反,当我想提供一些默认的基础架构代码和行为时,我会使用一个抽象类,并让客户端代码可以从这个抽象派生类,用一些自定义代码覆盖纯虚方法,并使用自定义代码完成此行为。 以 OpenGL 应用程序的基础架构为例。 您可以定义一个初始化 OpenGL、设置窗口环境等的抽象类,然后您可以从该类派生并实现自定义代码,例如渲染过程和处理用户输入:

// Abstract class for an OpenGL app.
// Creates rendering window, initializes OpenGL; 
// client code must derive from it 
// and implement rendering and user input.
class OpenGLApp

public:
  OpenGLApp();
  virtual ~OpenGLApp();
  ...

  // Run the app    
  void Run();


  // <---- This behavior must be implemented by the client ---->

  // Rendering
  virtual void Render() = 0;

  // Handle user input
  // (returns false to quit, true to continue looping)
  virtual bool HandleInput() = 0;

  // <--------------------------------------------------------->


private:
  //
  // Some infrastructure code
  //
  ... 
  void CreateRenderingWindow();
  void CreateOpenGLContext();
  void SwapBuffers();
;


class MyOpenGLDemo : public OpenGLApp

public:
  MyOpenGLDemo();
  virtual ~MyOpenGLDemo();

  // Rendering
  virtual void Render();  // implements rendering code

  // Handle user input
  virtual bool HandleInput(); // implements user input handling


  //  ... some other stuff
;

【讨论】:

@AdrianMaire 我的回答是技术;我不为任何人做“广告” // make MyAbstractClass not instantiable 的评论让我很困惑。是不是 void Method3(); 的减速使类抽象,因为它不是虚拟的? Method3 只是一个普通的方法,必须在代码的某处定义。【参考方案2】:

interface 主要是由 Java 流行起来的。 以下是interface 及其 C++ 等价物的性质:

    interface 只能包含无体抽象方法; C++ 等价物是纯 virtual 方法,尽管它们可以/不能有主体 interface 只能包含 static final 数据成员; C++ 等价于 static const 数据成员,它们是 编译时常量 多个interface 可以由Java class implemented,这个 需要工具,因为 Java class 只能继承 1 class;在virtual 的帮助下,C++ 立即支持多重继承 需要时的关键字

由于第 3 点,interface 的概念从未在 C++ 中正式引入。仍然可以灵活地做到这一点。

除此之外,您可以参考 Bjarne 的 FAQ 关于此主题。

【讨论】:

所以基本上,在 c++ 中,没有一个语言元素会强制你在 java 和 c# 中具有“类似接口”的行为。但由于“界面”主要是一个概念,您可以使用您提到的语言的特性来创建界面。 "C++ 等价物是纯虚方法,尽管它们可以/不能有主体" - 没有 can,纯虚定义在基类中没有主体,它们必须在派生类中有一个主体。此外,对于 C++ 中的多重继承,您不需要 virtual 关键字。事实上,使用多重继承的良好设计会避免使用virtual 关键字(好吧,如果可以的话,他们会尝试完全避免多重继承)。 课外身体是什么意思?根据定义,纯虚函数没有主体,并且对于派生类来说不是可选的覆盖,除非它们打算进一步派生,在这种情况下它们也是抽象的:ideone.com/hc1Zq8。 @Samaursa,这是一个如何定义 body of a pure virtual method的示例。 有趣的是:对于纯虚拟析构函数,你仍然应该有一个(空的)主体。【参考方案3】:

当需要一些通用实现时,将使用抽象类。如果您只想指定程序的某些部分也必须遵守的合同,则接口将是。通过实现一个接口,您保证您将实现某些方法。通过扩展一个抽象类,你继承了它的一些实现。因此,接口只是一个抽象类,没有实现任何方法(都是纯虚拟的)。

【讨论】:

“一个接口只是一个没有实现方法的抽象类” - 没有非静态数据成员,你会想到的。 我希望即使纯虚拟也能实现析构函数。 是的,我想我的意思是“什么都没有实现”。【参考方案4】:

纯虚函数多用于定义:

a) 抽象类

这些是基类,您必须从它们派生,然后实现纯虚函数。

b) 接口

这些是“空”类,其中所有函数都是纯虚函数,因此您必须派生然后实现所有函数。

纯虚函数实际上是在基类中没有实现,必须在派生类中实现的函数。

【讨论】:

【参考方案5】:

请不要将成员放入界面;虽然在措辞上是正确的。请不要“删除”接口。

class IInterface() 
 
   Public: 
   Virtual ~IInterface(); 
   … 
 

Class ClassImpl : public IInterface 
 
    … 
 

Int main() 
 

  IInterface* pInterface = new ClassImpl(); 
  … 
  delete pInterface; // Wrong in OO Programming, correct in C++.

【讨论】:

你能解释一下为什么不应该删除接口吗?在这个例子中,接口有一个虚拟析构函数。所以即使我们通过 IInterface 指针删除这个对象,ClassImpl 的析构函数也会被调用,不是吗? 对于 C++11 及更高版本,应该没有理由明确地新建/删除任何内容。您应该改用std::make_uniquestd::make_shared。这将防止内存泄漏和其他常见错误。

以上是关于C ++中的抽象类与接口[重复]的主要内容,如果未能解决你的问题,请参考以下文章

接口和类的区别

java中的抽象类与接口

抽象类与接口的区别

Java中接口抽象类与内部类学习

关于抽象类与接口

java 抽象类与接口