interface Stack{ void push(T val); T pop(); boolean isEmpty(); }
class ArrayStack implements Stack { void push(T val) {…} T pop() {…} boolean isEmpty() {…} private int tos; private T[]; }
class LinkedStack implements Stack { void push(T val) {…} T pop() {…} boolean isEmpty() {…} private Nodetos; }
Stack s; System.out.println("What kind of stack do you want? "); String answer = scanner.next(); if (answer.equals("array") s = new ArrayStack(); else s = new LinkedStack(); …
Stack
reference variable can be assigned
a reference to either the array or linked-list object.
Stack stack; // actual object — need to know size
Stack
(of some implementation) object here; not a reference
Stack
object and get a hint of what the actual implementation is
Stack *sp;
Stack
need to be abstract.
class Stack { public: virtual void push(int) = 0; virtual void pop() = 0; virtual bool isEmpty() = 0; };
class B { public: … virtual void f(); // expects/permits a derived class to override f polymorphically ally (i.e., with dynamic function resolution) … };
virtual
function resolution remains static
virtual void f() = 0;
class Derived : public Base { … };
class Shape { … }; class Circle : public Shape { … };
: public
in the class header means — the base class' functions
are public when called on objects of the derived class
class Vehicle { … }; class Car : public Vehicle { … };
Car
is-a Vehicle
: public
class Vector { 'growable' array and add-to-end / remove-from-end functions (in addition to random access via get/set) … // other vector-specific methods void (int val); // add to end; int remove(); // remove from end … // other vector-specific methods int get(int index); // this is one of them … }; class Stack : Vector { // note absence of public … will be discussed later … void push(int val) {add(val);} //leveraging base class functions int pop() {return remove();} … };
Stack
to be called with functions of the base class (e.g. get
of Vector
)
add
for push
)
and remove
for pop
class C { … private: int x; double d; }; C c1; C c2 = c1; // initializes c2 by copying c1's i and d to c2's i and d C c3; c3 = c2; // assigns c2's i and d to c3's i and d
class B { … }; class D { … private: B *bp; // Assume assigned a dynamically allocated B object at constructor time }; D d1; D2 d2 = d1;
template <typename T>
class Pair {
public:
Pair(T f, T s) : first(f), second(s) {} // member initialization list — Preferred to assigning in the body
T getFirst() {return first;}
T getSecond() {return second;}
void swap() {
T temp = first;
first = second;
second = temp;
}
private:
T first, second;
};
…
Pair<int> pi(2, 3);
Pair<string> ps("Hello", "Goodbye");
template <typename T> T max(T x, T y) { return x > y ? x : y; } … cout << max(10, 12) << endl; // instantiates maxand calls max(int, int) cout << max(10.0, 12.5) << endl; // instantiates max and calls max(double, double) //cout << max(10, 12.5) << endl; // illegal — ambiguous instantiation cout << max<int>(10, 12.5) << endl; // ok cout << max<double>(10, 12.5) << endl; // ok
<
operator defined for it
template <typename T> void sort(T arr[], int n) { for (int last = n-1; i > 0; i--) for (int i = 0; i < last; i++) if (arr[i] > arr[i+1]) { T temp = arr[i]; arr[i] = arr[i+1]; arr[i+1]= temp; } }
T
)
template <typename T> void sort(T arr[], int n, ??? gt) { for (int last = n-1; i > 0; i--) for (int i = 0; i < last; i++) if (gt(arr[i], arr[i+1])) { T temp = arr[i]; arr[i] = arr[i+1]; arr[i+1]= temp; } }
interface Comparator { int compare(Object obj1, Object obj2); } void sort(Object [] arr, Comparator comparator) { for (int last = arr.length-1; i > 0; i--) for (int i = 0; i < last; i++) if (comparator.compare(arr[i], arr[i+1] == 1) { Object temp = arr[i]; arr[i] = arr[i+1]; arr[i+1]= temp; } } class Employee { … String getName() {…}; int getID() {…}; … } Employee [] employees = new … class IDComparator implements Comparator { int compare(Object obj1, Object obj2) { Employee e1 = (Employee)obj1; Employee e2 = (Employee)obj2; return e1.getID().compareTo(e2.getID()); } } class NameComparator implements Comparator { int compare(Object obj1, Object obj2) { Employee e1 = (Employee)obj1; Employee e2 = (Employee)obj2; return e1.getName().compareTo(e2.getName()); } } sort (employees, new NameComparator()); … sort (employees, new IDComparator());
[1.1]
new
operator (similar to the that operator in Java — at least for this discussion)
should therefore be deleted when no longer needed — or the program risks running out of memory
new
/delete
is in the constructor/destructor, then the allocation is controlled by the
lifetime of the wrapping object