Nun, es geht um alles Abstraktion . Die Abstraktion ist besonders bei der Programmierung nützlich. Der Hauptvorteil ist die Fähigkeit, Realisierungsdetails zu verbergen. Man versteckt sie innerhalb eines Moduls (sog. "Server-Module") und stellt eine öffentliche Schnittstelle für andere Module (sog. "Client-Module") bereit. Und jetzt haben wir drei verschiedene Möglichkeiten:
Server-Modul kann eine abstrakte Datenstruktur (ADS) selbst.
In diesem Fall enthält er die ADS-Entität selbst. Die öffentliche Schnittstelle besteht aus einigen Prozeduren (und vielleicht einigen Konstanten).
Schnittstelle des Server-Moduls (stack_ads.h):
#ifndef STACK_ADS
#define STACK_ADS
const int capacity = 10;
void clear();
int size();
int pop();
void push(int value);
#endif STACK_ADS
Implementierung (stack_ads.cpp):
#include "stack_ads.h"
int items[capacity];
int top = -1;
void clear()
{
top = -1;
}
int size()
{
return top + 1;
}
int pop()
{
top -= 1;
return items[top + 1];
}
void push(int value)
{
top += 1;
items[top] = value;
}
Im Client-Modul (main.cpp) importieren wir das Server-Modul und verwenden die Datenstruktur direkt.
#include <iostream>
#include "stack_ads.h"
int main (int argc, char* const argv[])
{
push(1);
push(2);
push(3);
std::cout << pop() << std::endl;
std::cout << pop() << std::endl;
std::cout << pop() << std::endl;
return 0;
}
Server-Modul kann eine abstrakter Datentyp (ADT) in Form von struct/record.
Im Client-Modul können wir Variablen dieses Typs deklarieren. Da es einem Modul freisteht, mehr als eine Variable des exportierten Typs zu deklarieren, kann es mehr als eine Datenstruktur haben. Jede abstrakte Datenstruktur ist eine Variable vom abstrakten Datentyp.
Schnittstelle (stack_adt.h):
#ifndef STACK_ADT
#define STACK_ADT
const int capacity = 10;
typedef struct
{
int items[capacity];
int top;
} StackADT;
void clear(StackADT* stack);
int size(StackADT* stack);
int pop(StackADT* stack);
void push(StackADT* stack, int value);
#endif STACK_ADT
Implementierung (stack_adt.cpp):
#include "stack_adt.h"
void clear(StackADT* stack)
{
stack->top = -1;
}
int size(StackADT* stack)
{
return stack->top + 1;
}
int pop(StackADT* stack)
{
stack->top -= 1;
return stack->items[stack->top + 1];
}
void push(StackADT* stack, int value)
{
stack->top += 1;
stack->items[stack->top] = value;
}
Client-Modul:
#include <iostream>
#include "stack_adt.h"
int main (int argc, char* const argv[])
{
StackADT stack1;
StackADT stack2;
stack1.top = -1;
stack2.top = -1;
push(&stack1, 1);
push(&stack1, 2);
push(&stack1, 3);
std::cout << pop(&stack1) << std::endl;
std::cout << pop(&stack1) << std::endl;
std::cout << pop(&stack1) << std::endl;
push(&stack2, 10);
push(&stack2, 20);
push(&stack2, 30);
std::cout << pop(&stack2) << std::endl;
std::cout << pop(&stack2) << std::endl;
std::cout << pop(&stack2) << std::endl;
return 0;
}
Schließlich kann das Servermodul eine abstrakter Datentyp (ADT) in Form von Klasse .
Wenn unsere Sprache OOP unterstützt, können wir ADT mit Hilfe von Klassen beschreiben. Und im Client-Modul können wir wiederum Variablen dieses Typs deklarieren. In der objektorientierten Terminologie wird der Typ als Klasse und die Variable mit diesem Typ wird als Objekt .
Server-Modul-Schnittstelle (Stack.h):
#ifndef STACK
#define STACK
const int capacity = 10;
class Stack
{
public:
Stack();
void clear();
int size();
int pop();
void push(int value);
private:
int items[capacity];
int top;
};
#endif STACK
Implementierung (Stack.cpp):
#include "Stack.h"
Stack::Stack()
{
this->top = -1;
}
void Stack::clear()
{
this->top = -1;
}
int Stack::size()
{
return this->top + 1;
}
int Stack::pop()
{
this->top -= 1;
return this->items[this->top + 1];
}
void Stack::push(int value)
{
this->top += 1;
this->items[this->top] = value;
}
Die Unterschiede zwischen den beiden letzten Optionen sind:
- Die oben erwähnte Terminologie (Typ <-> Klasse, Variable <-> Objekt).
- In der Nicht-Klassen-ADT muss die formale Parameterliste jeder Prozedur eine Variable s vom Typ Stack enthalten. In der Klasse Stack wird die Angabe der Datenstruktur s nicht mit den anderen Formalparametern nach dem Namen der Prozedur aufgeführt, sondern steht allein in Klammern vor dem Namen der Prozedur. In der Smalltalk-Terminologie wird der formale Parameter vor dem Prozedurnamen als Empfänger .
- Der Ort der Verfahren. In der Nicht-Klassen-ADT befinden sich die Prozeduren außerhalb der Stack-Struktur. In der Klasse befinden sich die Prozeduren innerhalb der Klasse. In der objektorientierten Terminologie werden Prozeduren, die Empfänger haben und daher innerhalb eines Klassentyps enthalten sind, als Methoden .
Client-Code:
#include <iostream>
#include "stack.h"
int main (int argc, char* const argv[])
{
Stack stack1;
Stack stack2;
stack1.push(1);
stack1.push(2);
stack1.push(3);
std::cout << stack1.pop() << std::endl;
std::cout << stack1.pop() << std::endl;
std::cout << stack1.pop() << std::endl;
stack2.push(10);
stack2.push(20);
stack2.push(30);
std::cout << stack2.pop() << std::endl;
std::cout << stack2.pop() << std::endl;
std::cout << stack2.pop() << std::endl;
return 0;
}
0 Stimmen
Mögliche Duplikate von Merkmale der abstrakten Klasse
0 Stimmen
@MarkSeemann Ich habe es vor zwanzig Jahren gelesen, mein Freund. ADT ist kein OO-Konzept. Die meisten modernen Sprachen verwenden stattdessen generische Programmierung, um sie zu implementieren.
0 Stimmen
Ans: programmers.stackexchange.com/a/288504/114794
1 Stimmen
Die beste einfache Definition, die ich gefunden habe, stammt aus Cracking the Coding Interview von Gayle L.M.: "Ein abstrakter Datentyp wird durch sein Verhalten (seine Operationen) definiert. Die zugrunde liegende Implementierung kann variieren. Man könnte eine Prioritätswarteschlange mit einem Array oder einem Min- (oder Max-) Heap (oder vielen anderen Datenstrukturen) implementieren." Einige gängige abstrakte Datentypen (ADTs): Liste, Menge, Graph, Stapel, Warteschlange, Prioritätswarteschlange, usw.
0 Stimmen
ADT ist der Kern des OOP-Abstraktionsprinzips, das durch Polymorphie und Vererbung ergänzt werden sollte. Man könnte sagen, dass ADT (Abstraktion) die eigentliche Grundlage von OOP ist und die übrigen Prinzipien darauf aufbauen und sie ergänzen.