Abstract类是Abstract数据类型的一个例子吗?

时间:2018-02-17 08:45:10

标签: c++ polymorphism abstract-class adt

我对这两个感到困惑。我学到的是抽象数据类型是数据类型的数学模型,它指定了操作这些对象的对象和方法,而没有指定有关对象和方法的实现的细节。例如:抽象堆栈模型定义了一个堆栈,其中包含push和pop操作,用于在堆栈中插入和删除项目。我们可以通过使用链表,数组或类来以多种方式实现它。

现在,来到抽象类的定义,它是一个父类,它有一个或多个没有定义的方法(实现?)而且无法实例化(就像我们不能实现抽象栈一样)是,没有通过其中一个具体的数据结构定义堆栈的底层机制)。例如:如果我们有一个名为Mammal的抽象类,其中包含一个名为eat()的函数,我们不知道哺乳动物是如何吃的,因为哺乳动物是抽象的。虽然我们可以为母牛定义eat(),而母牛是哺乳动物的衍生类。这是否意味着哺乳动物作为adt和牛类是哺乳动物adt的实施?

如果我以任何方式错了,请纠正我。任何形式的帮助将非常感激。

3 个答案:

答案 0 :(得分:3)

  

抽象数据类型是数据类型的数学模型......

     

现在,来看抽象类的定义......

您需要区分理论数学模型和实际实施技术。

模型是由人们创造的,以便以一种易于理解,概括的方式轻易地推理问题。

同时,编写实际代码是为了工作并完成工作。

“抽象数据类型”是模型。 “抽象类”是一种编程技术,其中一些编程语言(C ++,C#,Java)支持语言层次。

“抽象数据类型”让您思考和讨论关于问题的解决方案,而不会因为不必要的(此时)实施细节而使您的大脑过载。当你需要一个FIFO数据结构时,你只说“stack”,而不是“带有指向头节点的指针的双向链表和能够......”

“抽象类”允许您编写代码一次,然后再重复使用(因为这是OOP的重点 - 代码重用)。当您看到几种类型具有通用接口和功能时 - 您可以创建“抽象类”并将其功能的交集放在内部,同时仍然能够依赖尚未实现的功能,这些功能将通过某种具体类型实现后来。这样,您只需编写一次代码,以后需要更改代码时 - 只有一个地方可以进行更改。

注意:
虽然,在 C ++ ISO标准(至少在草稿中)中有注释:

  

注意:抽象类机制支持一般概念的概念,   如形状,其中只有更具体的变体,如圆形   和方,实际上可以使用。

但这只是一个注释。真正的定义是:

  

如果一个类至少有一个纯(也就是未实现的)虚函数,那么它就是抽象的。

导致明显的约束:

  

除了作为子对象之外,不能创建抽象类的任何对象   一个派生自它的类

就个人而言,我喜欢C ++(与C#和Java不同)没有关键字“abstract”。它只有类型继承和虚函数(可能仍未实现)。这有助于您专注于实际问题:在需要的地方继承,在必要时覆盖。

简而言之,使用OOP - 务实。

答案 1 :(得分:1)

术语“抽象数据类型”与C ++中的任何内容都没有直接关系。所以abstract class是在给定语言中实现抽象数据类型的潜在实现策略之一。但是还有很多技术可以做到这一点。

所以abstract base classes允许你定义一组派生类,并保证所有接口(声明)都有一个实现,如果没有,编译器会抛出一个错误,因为你不能得到一个由于缺少方法定义,因此您的类的实例。

但您也可以使用compile time polymorphism和CRTP等相关技术来获取抽象数据类型。

所以必须决定你需要哪些功能以及你想要支付的价格。 Runtime polymorphism附带了vtable和vtable调度的额外费用,但有late binding的好处。 Compile time polymorphism带来了更好的可优化代码的好处,具有更快的执行速度和更少的代码大小。如果没有实现接口,两者都会给出错误,至少在链接器阶段是这样。

但是具有多态性,独立运行时或编译时的抽象数据类型不是1:1的关系。通过简单地定义一个必须某处实现的接口,也可以给出抽象的东西。

简而言之:抽象数据类型不是直接用c ++表示,而抽象基类是c ++技术。

答案 2 :(得分:0)

  

Abstract类是Abstract数据类型的一个例子吗?

是的,但在C ++中,抽象类已成为抽象数据类型中越来越少见的例子,因为泛型编程通常是一种更好的选择。

  

Ex:抽象堆栈模型使用push和pop定义堆栈   在堆栈中插入和删除项目的操作。我们可以   通过使用链表,数组或类,以多种方式实现它。

C ++ std::stack类模板或多或少都是这样的。它具有成员函数pushpop,并且它是根据Container类型参数实现的,默认为std::deque

对于具有链接列表的实现,您需要键入std::stack<int, std::list<int>>。但是,数组不能用于实现堆栈,因为堆栈可以增长和缩小,并且数组具有固定的大小。

理解std::stack与抽象类或运行时多态性完全无关,这一点非常重要。没有涉及一个虚拟功能。

  

现在,来到抽象类的定义,它是一个父类   它有一个或多个没有的方法   定义(实现?)并且无法实例化

是的,这正是C ++中抽象类的定义。

理论上,这样的堆栈类可能如下所示:

template <class T>
class Stack
{
public:
    virtual ~Stack() = 0;
    virtual void push(T const& value) = 0;
    virtual T pop() = 0;
};

在此示例中,元素类型仍然是通用的,但容器的实现意味着由具体的派生类提供。这种容器设计在其他语言中是惯用的,但在C ++中则不然。

  

就像我们无法实现抽象堆栈一样,没有通过其中一个具体数据结构定义堆栈的底层机制

是的,如果没有提供容器类型参数,你就无法使用std::stack(但这是不可能的,因为它有默认的std::deque参数),你也无法实例化Stack<int> my_stack;