Classes with dynamic objects List as a (dynamic) class ‘Class’ matters! global local int x; int x; void f() { void f() { x=10; } class A { public int x; int x; x=10; void.

Download Report

Transcript Classes with dynamic objects List as a (dynamic) class ‘Class’ matters! global local int x; int x; void f() { void f() { x=10; } class A { public int x; int x; x=10; void.

Classes with dynamic objects
List as a (dynamic) class
‘Class’ matters!
global
local
int x;
int x;
void f() {
void f() {
x=10;
}
class A {
public
int x;
int x;
x=10;
void f();
}
}
main() {
main() {
main() {
x=0;
public
f();
}
x=0;
A a;
f();
a.x = 0;
a.f();
}
}
Public or private?
class A {
public:
int main() {
void f();
A a;
int x;
a.f();
private:
int y;
cout << a.x << endl;
}
cout << a.y << endl; // no!!!
void A::f() {
a.x = 1000;
x=10;
y=100;
}
a.y = 10000; // no!!!
}
Abstract Data Type: public function, private data
class A {
int main()
public:
{
A();
A a;
int f();
cout << a.f(); // not a.x!!!
private:
int x;
}
A b(a);
A c;
c = a; // member-wise copy
}
A::A() {
x=0;
}
int A::f() {
return x;
}
Objects are calling member funtions
(public interface)
Member functions are using member
variables (private data)
Objects are not directly dependent on
implementation (private data)
Static and dynamic
Static variables (objects)
Dynamic variables (objects)
A (direct) named memory location
A static part (pointer) + (indirect)
nameless memory location
(dynamic part)
int a;
int* pa;
a = 20;
pa = new int;
*pa = 20;
a
20
static
20
pa
static
dynamic
classes
Only static member variables
At least one pointer variable (I.e.
dynamic variable)
class A {
class B {
public:
public:
B();
A();
B(const B& b);
private:
~B();
int x;
private:
}
int* px;
}
(Must) a defaut value constructor A() for
initialisation
(Must) a defaut value constructor for
Creation by new + initialiation
‘copy constructor’ automatically privided (Must) redefine ‘copy constructor’
No destructor
(Must) the destructor
‘assignment’ automatically provided
(Must) redefine ‘assignment’ (do later)
class B {
B::B() {
px = new int;
public:
*px = 0;
B();
B(const B& b);
}
~B();
private:
B::B(const B& b) {
px = new int;
int* px;
(*px) = *(b.px);
}
}
B::~B() {
delete px;
}
Automatic behavior of constructors/destructor
All constructors/destructor have automatic behavior, they are
called ‘implicitly’!!! (that’s why they have standard names!)
Constructors are called when creating variables and other occasions:
A a; // implicitly call the default value constructor A::A();
A b(a); // implicitly call the copy constructor A::A(const A& a);
Destructors are called when the variables go out of scope
void somefunction() {
B b;
};
Example of a (dynamic)
class: linked list class
linked lists: definition
struct Node{
int data;
Node* next;
};
bool listEmpty(NodePtr head) {
}
int getHead(NodePtr head) {
typedef Node* NodePtr;
NodePtr head;
}
NodePtr getRest(NodePtr head) {
}
NodePtr addHead(NodePtr head, int newdata)
{
}
void delHead(NodePtr& Head){
}
Usage:
void main(){
NodePtr Head1=NULL, Head2 = NULL, Head;
addHead(Head1, 50);
addHead(Head1, 40);
addHead(Head1, 30);
addHead(Head1, 20);
cout << "List 1: " << endl;
DisplayList(Head1);
cout << "Length of Head1 list: " << length(Head1) << endl;
cout << "Recursive length of Head1 list: " << lengthRec(Head1) << endl;
if(isPalindrome(Head1))
cout << "Head1 list is palindrome" << endl;
else
cout << "Head1 list is not palindrome" << endl;
addHead(Head2, 25);
addHead(Head2, 35);
addHead(Head2, 45);
addHead(Head2, 35);
addHead(Head2, 25);
cout << "List 2: " << endl;
DisplayList(Head2);
cout << "Length of Head2 list: " << length(Head2) << endl;
cout << "Recursive length of Head2 list: " << lengthRec(Head2) << endl;
if(isPalindrome(Head2))
cout << "Head2 list is palindrome" << endl;
else
cout << "Head2 list is not palindrome" << endl;
Head = mergeLists(Head1, Head2);
cout << "Merged List: " << endl;
DisplayList(Head);
cout << "Length of Merged list: " << length(Head) << endl;
cout << "Recursive length of Merged list: " << lengthRec(Head) << endl;
if(isPalindromeRec(Head))
cout << "Merged list is palindrome" << endl;
else
cout << "Merged list is not palindrome" << endl;
cout << "check the list again:" << endl;
DisplayList(Head);
Make an Abstract Data Type


One more example of ADT:
 integer linked list using class
A class with dynamic objects:
 Copy constructor
 Destructor
struct Node{
public:
int data;
Node* next;
};
typedef Node* Nodeptr;
‘new’ member functions
class list {
public:
list();
// constructor
list(const list& list1); // copy constructor
~list();
// destructor
bool empty() const;
int headElement() const;
// boolean function
// access functions
void addHead(int newdata);
void deleteHead();
// add to the head
// delete the head
int length() const;
void print() const;
private:
Nodeptr head;
};
// utility function
// output
‘old’ operations
How to use it
void main(){
list L;
L.print();
L.addHead(30);
L.print();
L.addHead(13);
L.print();
L.addHead(40);
L.print();
L.addHead(50);
L.print();
list N(L);
N.print();
}
// constructor called automatically here for L
{ }
{ 30 }
{ 13 30 }
{ 40 13 30 }
{ 50 40 13 30 }
{ 50 40 13 30 }
list R;
R.print();
{ }
if(R.empty())
cout << "List R empty" << endl;
L.deleteHead();
L.print();
{ 40 13 30 }
L.deleteHead();
L.print();
{ 13 30 }
if(L.empty())
cout << "List L empty" << endl;
else{
cout << "List L contains " << L.length() << " nodes" << endl;
cout << "Head element of list L is: " << L.headElement() << endl;
}
// destructor called automatically here for L
Implementation
Some simple member functions:
list::list(){
head = NULL;
}
bool list::empty() const{
if(head==NULL)
return true;
else
return false;
}
int list::headElement() const {
if(head != NULL)
return head->data;
else{
cout << "error: trying to find head of empty list" << endl;
exit(1);
}
}
(explicitly defined) copy constructor:
list::list(const list& list1) {
head = NULL;
Nodeptr cur = list1.head;
while(cur != NULL) {
// addEnd(cur->data);
addHead(cur->data); // inverse list order
cur = cur->next;
}
}
Destructor: deallocation function
list::~list(){
Nodeptr cur;
while(head!=NULL){
cur = head;
head = head->next;
delete cur;
}
}
Adding an element to the head:
void list::addHead(int newdata){
Nodeptr newPtr = new Node;
newPtr->data = newdata;
newPtr->next = head;
head = newPtr;
}
Deleting the head:
void list::deleteHead(){
if(head != NULL){
Nodeptr cur = head;
head = head->next;
delete cur;
}
}
Print the list:
void list::print() const{
cout << "{";
Nodeptr cur = head;
while(cur != NULL){
cout << cur->data << " ";
cur = cur->next;
}
cout << "}" << endl;
}
Computing the number of elements of a given list:
int list::length() const{
int n=0;
Nodeptr cur = head;
while(cur != NULL){
n++;
cur = cur->next;
}
return n;
}
struct Node{
public:
int data;
Node* next;
};
typedef Node* Nodeptr;
class list {
public:
list();
// constructor
list(const list& list1); // copy constructor
const list& operator=(const list& list1); // assigment, l = l1;
~list();
// destructor
bool empty() const;
int head() const;
list remaining() const;
// boolean function
// access functions
// the list with the head removed
void insert(int d);
void delete(int d);
// insertion
// deletion
int length() const;
void print() const;
private:
Nodeptr head;
// utility function
//
Interface functions
};
An almost ideal list class
copy constructor:
list::list(const listClass& list1) {
head = NULL;
Nodeptr cur = list1.head;
while(cur != NULL) {
// addEnd(cur->data);
addHead(cur->data); // inverse list order
cur = cur->next;
}
Operator assignment, ‘deep copy’
}
Const list& operator=(const list& list1) {
if (this != &list1) {
head = NULL;
Nodeptr cur = list1.head;
while(cur != NULL) {
// addEnd(cur->data);
addHead(cur->data); // inverse list order
cur = cur->next;
}
return *this;
}
Delete[] head;
Big three: copy constructor, operator=, destructor
Usage difference
list l1, l2;
node* head1, head2;
head1 = NULL; head2 = NULL
l1.addEnd(5);
addEnd(head1,5);
list l3(l1);
node* head3 = NULL;
l3 = l2;
copylist(head1, head3);
head3 = head2;