Object-Oriented Programming and Data Structures COMP2012: Data Abstraction & Classes
Object-Oriented Programming and Data Structures COMP2012: Data Abstraction & Classes
Gary Chan
Brian Mak
Desmond Tsoi
Name: Becky
Father: unknown
Mother: unknown
Grand Fathers: unknown, unknown
Grand Mothers: unknown, unknown
Name: Claire
Father: Arthur
Mother: Becky
Grand Fathers: unknown, unknown
Grand Mothers: unknown, unknown
Name: Eddy
Father: unknown
Mother: Claire
Grand Fathers: unknown, Arthur
Grand Mothers: unknown, Becky
class Person
{
private:
char* _name;
int _age;
Person *_father, *_mother, *_child;
public:
Person(const char* my_name, int my_age, Person* my_father = nullptr,
Person* my_mother = nullptr, Person* my_child = nullptr);
˜Person();
// Helper function
void print_parent(Person* parent)
{
if (parent)
parent->print_name();
else
cout << "unknown";
}
if (_father) {
f_grandmother = _father->mother();
f_grandfather = _father->father();
}
if (_mother) {
m_grandmother = _mother->mother();
m_grandfather = _mother->father();
}
int main()
{
Person arthur("Arthur", 65, nullptr, nullptr, nullptr);
Person becky("Becky", 63, nullptr, nullptr, nullptr);
Person claire("Claire", 32, &arthur, &becky, nullptr);
Person eddy("Eddy", 4, nullptr, &claire, nullptr);
arthur.have_child(&claire);
becky.have_child(&claire);
claire.have_child(&eddy);
Data Abstraction
1 data
3
size
top
top
-999
top
(latest item)
-999 1 2
class Stack
{
private:
int data[BUFFER_SIZE]; // Use an array to store data
int top_index; // Starts from 0; -1 when empty
public:
// CONSTRUCTOR member functions
Stack(); // Default constructor
struct ll_inode
{
int data;
ll_inode* next;
};
class Stack
{
private:
ll_inode* head; // head of a linked list of int's
public:
// CONSTRUCTOR member functions
Stack(); // Default constructor
// ACCESSOR member functions: const => won't modify data members
bool empty() const; // Check if the stack is empty
bool full() const; // Check if the stack is full
int size() const; // Give the number of data currently stored
int top() const; // Retrieve the value of the top item
// MUTATOR member functions
void push(int); // Add a new item to the top of the stack
void pop(); // Remove the top item from the stack
};
{gchan, mak, desmond}@cse.ust.hk COMP2012 (Spring 2018) p.17
Information Hiding Again
struct Stack
{
int data[BUFFER_SIZE]; // Use an array to store data
int top_index; // Starts from 0; -1 when empty
class X { int a; };
class Y { int a; };
class W { int a; };
class W { int b; }; // Error, double definition
X x;
Y y;
class Cell
{
int info;
Cell* next;
};
class Stack
{
int size;
Cell* data; // Points to a (forward-declared) Cell object
Cell x; // Error: Cell not defined yet!
};
1. Within the class body, then they are inline functions. The
keyword inline is optional in this case.
class Stack
{
...
void push(int x) { if (!full()) data[++top_index] = x; }
void pop() { if (!empty()) --top_index; }
};
Or,
class Stack
{
...
inline void push(int x) { if (!full()) data[++top_index] = x; }
inline void pop() { if (!empty()) --top_index; }
};
{gchan, mak, desmond}@cse.ust.hk COMP2012 (Spring 2018) p.25
Class Member Functions ..
2. Outside the class body, then add the prefix consisting of the
class name and the class scope operator ::
(Any benefits of doing this?)
/* File: stack.h */
class Stack
{
...
void push(int x);
void pop();
};
/* File: stack.cpp */
void Stack::push(int x) { if (!full()) data[++top_index] = x; }
void Stack::pop() { if (!empty()) --top_index; }
int main()
{
Stack x;
x.push(2); // OK: push( ) is public
cout << x.top_index; // Error: cannot access top_index
return 0;
}
int main()
{
Stack x(2), y(3);
push( )
x.push(1);
y.push(2); pop( )
y.pop();
}
public:
Complex(float r, float i) { real = r; imag = i; }
void print() { cout << "(" << real << " , " << imag << ")" << endl; }
int main()
{
Complex y(3, 4); y.print();
cout << endl << "Return its pointer by value" << endl;
x.add2(y)->print();
x.print();
return 0;
}
{gchan, mak, desmond}@cse.ust.hk COMP2012 (Spring 2018) p.36
Return by Value and Return by Reference
There are 2 ways to pass parameters to a function
pass-by-value (PBV)
pass-by-reference (PBR)
lvalue reference: that is what you learned in the past and
we’ll keep just saying reference for lvalue reference.
rvalue reference (C++11)
Similarly, you may return from a function by returning an object’s
value: the function will make a separate copy of the object
and return it. Changes made to the copy have no effect on
the original object.
(lvalue) reference: the object itself is passed back! Any
further operations on the returned object will directly modify
the original object as it is the same as the returned object.
rvalue reference: we’ll talk about this later.
{gchan, mak, desmond}@cse.ust.hk COMP2012 (Spring 2018) p.37
Part IV
const-ness
return 0;
}
/* File: const-object-date.h */
class Date // There are problems with this code; what are they?
{
private:
int year, month, day;
public:
Date() { cin >> year >> month >> day; }
Date(int y, int m, int d) { year = y; month = m; day = d; }
void print()
{ cout << year << "/" << month << "/" << day << endl; }
};
int main() // There are problems with this code; what are they?
{
const Date WW2(1945, 9, 2); // World War II ending date
Date today;
WW2.print();
today.print();
return 0;
}
{gchan, mak, desmond}@cse.ust.hk COMP2012 (Spring 2018) p.42
const Member Functions
public:
Date() { cin >> year >> month >> day; }
Date(int y, int m, int d) { year = y; month = m; day = d; }
void add_month() { month += 1; }; // Will be an inline function
int main()
{
char s[] = "COMP2012"; // Usual initialization in the past
char p[] {"MATH1013"}; // C++11 style of uniform initialization
int* pi = &i;
*pi += 20; // OK
pic = pi; // OK
*pic += 20; // Error! Can't change *pi thru pic