User Tools

Site Tools


cpp:interfaces

Interfaces

Η C++ δεν διαθέτει interfaces με τον αυστηρά ορισμένο τρόπο που αυτά ορίζονται στη Java. Αντ' αυτού υλοποιεί την λειτουργικότητα των interfaces μέσω abstract κλάσεων, δηλαδή κλάσεων που δεν μπορούν να δώσουν αντικείμενα. Στο παράδειγμα που ακολουθεί ορίζουμε το interface Stack το οποίο μπορεί να αποθηκεύει ακεραίους.

Η abstract base class Stack έχει δύο υποκλάσεις την κλάση ArrayStack που υλοποιεί τη στοίβα μέσω ενός πίνακα και την κλάση LinkedStack που υλοποιεί τη στοίβα μέσω απλά συνδεδεμένης λίστας.

Stack.h
#include <iostream>
using namespace std;
 
#ifndef __STACK_H__
#define __STACK_H__
 
class Stack {
  public:
    virtual int size()=0;
    virtual void push(int o)=0;
    virtual int pop()=0;
    virtual int top()=0;
};
#endif
ArrayStack.h
#include <iostream>
using namespace std;
 
#include "Stack.h"
 
#ifndef __ARRAYSTACK_H__
#define __ARRAYSTACK_H__
 
class ArrayStack : public Stack {
  int *array;
  int stackSize, capacity;
  public:
    ArrayStack(int capacity=16);
    int size();
    void push(int o);
    int pop();
    int top();
};
#endif
ArrayStack.cpp
#include "ArrayStack.h"
 
ArrayStack::ArrayStack(int cap) {
  capacity = cap;
  stackSize = 0;
  array = new int[capacity];
}
 
int ArrayStack::size() {
  return stackSize;
}
 
void ArrayStack::push(int o) {
  if(stackSize==capacity) {
    int *_array = new int[2*capacity];
    for(int i=0; i<stackSize; i++)
      _array[i] = array[i];
    delete[] array;
    array = _array;
  }
  array[stackSize++] = o;
}
 
int ArrayStack::pop() {
  return array[--stackSize];
}
 
int ArrayStack::top() {
  return array[stackSize];
}
LinkedStack.h
#include <iostream>
using namespace std;
 
#include "Stack.h"
 
#ifndef __LINKEDSTACK_H__
#define __LINKEDSTACK_H__
 
class LinkedNode {
  int element;
  LinkedNode *next;
public: 
  LinkedNode(LinkedNode *nxt, int e); 
  LinkedNode(int e); 
  int getElement();
  LinkedNode* getNext();
  void setElement(int e);
  void setNext(LinkedNode *nxt);
};
 
class LinkedStack : public Stack {
  int stackSize;
  LinkedNode *head;
public:
  LinkedStack();
  int size();
  void push(int o);
  int pop();
  int top();
};
#endif
LinkedStack.cpp
#include "LinkedStack.h"
 
/* LinkedNode function 
 * */
 
LinkedNode::LinkedNode(LinkedNode *nxt, int e) {
  next = nxt;
  element = e;
}
 
LinkedNode::LinkedNode(int e) : LinkedNode(NULL,e) { } 
int LinkedNode::getElement() { return element; }
LinkedNode* LinkedNode::getNext() { return next; } 
void LinkedNode::setElement(int  e) { element = e; }
void LinkedNode::setNext(LinkedNode *nxt) { next = nxt; }
 
/* LinkedStack function 
 * */
 
LinkedStack::LinkedStack() {
  stackSize = 0;
  head = NULL;
}
 
int LinkedStack::size() { return stackSize; }
 
void LinkedStack::push(int o) {
  LinkedNode *node = new LinkedNode(head, o);
  head = node;
  stackSize++;
}
 
int LinkedStack::pop() {
  if(size()==0)
    return -1;
  LinkedNode *node = head;
  head = head->getNext();
  int ptr = node->getElement();
  delete node;
  stackSize--;
  return ptr;
}
 
int LinkedStack::top() {
  return head->getElement();
}
StackUsage.cpp
#include "ArrayStack.h"
#include "LinkedStack.h"
 
#define ARRAY_SIZE 10
 
void invertArray(int array[], int arraySize, Stack &stack) {
  for(int i=0; i<arraySize; i++)
    stack.push(array[i]);
 
  for(int i=0; i<arraySize; i++)
    array[i] = stack.pop();
}
 
int main() {
 
  //ArrayStack st;
  LinkedStack st;
  int array[] = { 100, 99, 98, 97, 96, 95, 94, 93, 92, 91 };  
 
  for(int e:array)
    cout << e << endl;
  cout << endl;
 
  invertArray(array, ARRAY_SIZE, st);
 
  for(int e:array)
    cout << e << endl;
}

Το Makefile που μεταγλωττίζει τον παραπάνω κώδικα είναι το εξής:

Makefile
StackUsage: ArrayStack.o LinkedStack.o
	g++ -Wall -g -std=c++11 StackUsage.cpp ArrayStack.o LinkedStack.o -o StackUsage
 
ArrayStack.o: ArrayStack.cpp ArrayStack.h
	g++ -Wall -g -std=c++11 ArrayStack.cpp -c
 
LinkedStack.o: LinkedStack.cpp LinkedStack.h
	g++ -Wall -g -std=c++11 LinkedStack.cpp -c
 
clean:
	rm *.o StackUsage

Από τον παραπάνω κώδικα παρατηρούμε ότι η abstract κλάση Stack παρέχει μία σειρά από virtual μεθόδους οι οποίες υλοποιούνται από τις κλάσεις ArrayStack και LinkedStack. Η μέθοδος invertArray χρησιμοποιεί την abstract κλάση Stack ως interface. Ανάλογα με το είδος του αντικειμένου τύπου Stack με το οποίο θα κληθεί ο παραπάνω κώδικας η εσωτερική υλοποίηση της στοίβας θα είναι διαφορετική. Ο κώδικας όμως που χρησιμοποιεί το interface της στοίβας παραμένει αμετάβλητος, ανεξάρτητα από την εσωτερική υλοποίηση.

Τα interfaces στη C++ υλοποιούνται αποκλειστικά μέσω abstract κλάσεων που περιέχουν pure virtual συναρτήσεις. Είναι προφανές ότι μία abstract κλάση εκτός από pure virtual συναρτήσεις μπορεί να περιέχει και virtual συναρτήσεις και κανονικές συναρτήσεις, αλλά και μεταβλητές (πεδία). Η παραπάνω παραδοχή “θολώνει” λίγο την έννοια του interface στη C++, καθώς επιτρέπει να υπάρχουν δεδομένα και default υλοποιήσεις σε ένα interface. Σε κάθε περίπτωση, εάν μία κλάση περιέχει μόνο pure virtual συναρτήσεις μπορείτε να θεωρήσετε ότι αντιπροσωπεύει ένα interface.

cpp/interfaces.txt · Last modified: 2021/05/07 08:42 (external edit)