Group the data and allowable operations into one logical unit. An abstract data type is defined by the type of data to be stored (but not how it may be stored, i.e. no implementation of the storage) and the operations that will be allowed on the data. Again, the operations are defined, but not implemented. Another word for this bundling is encapsulation. Data and operations are combined in the same "capsule".
concepts:
We wish to define a Matrix data type that stores our 2-dimensional arrays and performs the usual arithmetic operations on them. Here is the ADT definition:
Matrix ADT:
data:
the size of the matrix (number of rows and columns)
a 2-d array of entries (say of floats)
operations:
arithmetic operations * + - (binary subtraction)
- (unary minus)
transpose
inverse
definition of operations:
* (multiplication):
if C = A*B, then:
A.cols = B.rows = N;
C[i][k] = A[i][1]*b[1][k] + A[i][2]*B[2][k] + ...
+ A[i][N]*B[N][k].
+ (addition):
if C = A+B then:
A.cols = B.cols; A.rows = B.rows;
C[i][k] = A[i][k] + B[i][k]
- (subtraction): defined similarly
- (unary minus): negate all entries
transpose:
Transpose(A).rows = A.cols;
Transpose(A).cols = A.rows;
Transpose(A)[i][j] = A[j][i];
inverse (for 2x2 only!!):
define det(A) = A[0][0]*A[1][1] - A[0][1]*A[1][0]
Inv(A)[0][0] = A[1][1]/det(A);
Inv(A)[0][1] = -A[1][0]/det(A);
Inv(A)[1][0] = -A[0][1]/det(A);
Inv(A)[1][1] = A[0][0]/det(A);
Notice no mention is made here of implementation.We have not specified how the data is to be stored (only that it is conceptualized as a 2-dimensional array), nor have I said how to implement the operations: which algorithms to use. This is an "abstract" definition of the data and operations.
C++ classes are a way to implement ADTs. A class is similar to a struct in C (or C++) with some important differences:
Thus, the class enforces abstraction by having private members that can be accessed only by other (public) member functions. And it enforces encapsulation by including both data and functions in the class declaration.
Here is a class declaration of the Matrix ADT. For simplicity, not all of the operations are included.
class Matrix
{
private: // data members
int rows, cols; // dimensions of matrix
double *m; // pointer to array
public: // member functions and friends
// CONSTRUCTORS
// constructor: this one takes size parameters,
Matrix( int r = 0, int c = 0 );
// copy constructor: takes another Matrix as parameter
Matrix( Matrix & );
// DESTRUCTOR
// destructor: free the memory, assign pointer to NULL
~Matrix() { delete [] m; m = NULL; }
// overloaded assignment operator
const Matrix & operator = ( const Matrix &M );
// FRIENDS (non-member functions with access to private
// data members)...
// overloaded output operator
friend ostream & operator << ( ostream & os, const Matrix &M );
// arithmetic operators...
// overloaded multiplication operator
friend const Matrix operator * ( const Matrix &M1, const Matrix &M2 );
// overloaded addition operator
friend const Matrix operator + ( const Matrix &M1, const Matrix &M2 );
};
Points to note:
cout << A;If it were declared as a member, then you would have to write:
A << cout;to get the same result. This would be confusing, to say the least! This will be explained in more detail later.
Insertion and deletion, both at one end of the list (called the top).
Stacks follow LIFO order: last in, first out.
Data implementation:
Implementation of operations:
Both operations take O(1) time, obviously.