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++ 中的 interface
和 abstract 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
implement
ed,这个
需要工具,因为 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_unique
或std::make_shared
。这将防止内存泄漏和其他常见错误。以上是关于C ++中的抽象类与接口[重复]的主要内容,如果未能解决你的问题,请参考以下文章