Download presentation
Presentation is loading. Please wait.
Published byAmanda Armstrong Modified over 8 years ago
1
Object Oriented Programming COP3330 / CGS5409
2
Aggregation / Composition Dynamic Memory Allocation
3
Aggregation (or composition) is a relationship between objects Implemented by embedding an object of one class type (or a pointer or reference) inside as member data of another class type This is the idea of objects embedded inside other objects (components making up the "aggregate")
4
Often known as the "has-a" relationship: We might place an Engine object inside a Car object as member data, because a "car has an engine" We could place 52 Card objects as member data of class Deck, because a "deck has 52 cards"
5
class Timer ◦ A Timer object consists of two Displays; one for hours and one for minutes class Display ◦ A Display object stores and displays a single integer.
6
class Display { public: ◦ Display(int lim);// Initialize a new Display object. void increment();// Add 1 to value. bool setValue(int val);// Set the value. int getValue() const;// Return the current value. int getLimit() const;// Return the limit void show() const;// Show the current value. private: const int LIMIT;// largest possible value int value;// current value (0.. limit - 1) };
7
class Timer { public: Timer();// Initialize a new Timer object 00:00 Timer(int h, int m);// Initialize a new Timer object // to h hours and m minutes void increment();// Add 1 minute to timer. bool set(int h, int m);// Set Timer to h hours and m minutes void show() const;// Show hours and minutes. Timer add(const Timer& t) const; // add two Timer objects together private: Display hours,// two displays, one for hours, minutes;// and one for minutes };
8
Two Display objects are used as member data in the Timer class declaration – variables: hours and minutes class Timer { public: // public member functions private: // Display objects declared as private data of a Timer object Display hours, minutes; };
9
Always pay attention to context, including who is the intended "user" of any given class. In the case of aggregation, the containing class is the "user" of the embedded objects. The user of the Timer is the main program (so the main program will be calling the timer's functions) The user of the Display objects is the Timer object (so the Timer object will be calling Display functions through the objects hours and minutes, because those variables are in scope)
10
When an object is created, its constructor runs, but also must invoke the constructors of any embedded objects. If nothing special is done, it will invoke the default constructor, if there is one. To invoke a constructor with parameters for an embedded object, use the initialization list
11
A SodaMachine object is a that contains (and handles communications among) other embedded objects: A ChangeCounter, to manage transactions 5 Dispenser objects, for each type offered Full source code: ◦ http://www.cs.fsu.edu/~jestes/cop3330/examples /machine/
12
class CoinCounter { public: CoinCounter(int initial = 100);// Initialize a counter, setting // available change. int CurrentAmount();// Report amount tendered so far. void AcceptCoin(int amt);// Handle coin insertion. void TakeAll();// Accept all coins in response to // a sale. void DispenseChange(int amt);// Return change, if possible. private: int amount;// the amount tendered so far int available;// the amount available for // making change };
13
class Dispenser { public: Dispenser(int num = 24);// Initialize with // default num cans. bool HandleButton();// Try to make a sale private: int numCans;// the number of cans // available };
14
class SodaMachine { public: SodaMachine();// Initialize a machine. void DoCommand(char cmd);// process a command from the user private: CoinCounter counter;// A soda machine contains a coin dispenser, Dispensercola,// five can dispensers, lite, root, orange, water; int price;// and the price of a can of soda. void DoCoin(char cmd);// Handle a coin event. void DoSelection(char cmd);// Handle a drink button press. };
15
There are two ways that memory gets allocated for data storage: Compile Time (or static) Allocation ◦ Memory for named variables is allocated by the compiler ◦ Exact size and type of storage must be known at compile time ◦ For standard array declarations, this is why the size has to be constant Dynamic Memory Allocation ◦ Memory allocated "on the fly" during run time ◦ dynamically allocated space usually placed in a program segment known as the heap or the free store ◦ Exact amount of space or number of items does not have to be known by the compiler in advance. ◦ For dynamic memory allocation, pointers are crucial
16
We can dynamically allocate storage space while the program is running, but we cannot create new variable names "on the fly" For this reason, dynamic allocation requires two steps: ◦ Creating the dynamic space. ◦ Storing its address in a pointer (so that the space can be accessed) To dynamically allocate memory in C++, we use the new operator.
17
De-allocation is the "clean-up" of space being used for variables or other data storage Compile time variables are automatically de- allocated based on their known extent (this is the same as scope for "automatic" variables) It is the programmer's job to de-allocate dynamically created space To de-allocate dynamic memory, we use the delete operator
18
To allocate space dynamically, use the unary operator new, followed by the type being allocated. new int; // dynamically allocates an int new double; // dynamically allocates a double If creating an array dynamically, use the same form, but put brackets with a size after the type: new int[40]; // dynamically allocates an array of 40 ints new double[size]; // dynamically allocates array of size doubles Note that the size can be a variable!
19
These statements above are not very useful by themselves, because the allocated spaces have no names! BUT, the new operator returns the starting address of the allocated space, and this address can be stored in a pointer: int * p; // declare a pointer p p = new int; // dynamically allocate an int and load address into p double * d; // declare a pointer d d = new double; // dynamically allocate a double and load address into d // we can also do these in single line statements int x = 40; int * list = new int[x]; float * numbers = new float[x+10]; Notice that this is one more way of initializing a pointer to a valid target (and the most important one).
20
So once the space has been dynamically allocated, how do we use it? For single items, we go through the pointer. Dereference the pointer to reach the dynamically created target: int * p = new int;// dynamic integer, pointed // to by p *p = 10;// assigns 10 to the // dynamic integer cout << *p;// prints 10
21
For dynamically created arrays, you can use either pointer-offset notation, or treat the pointer as the array name and use the standard bracket notation: double * numList = new double[size];// dynamic array for (int i = 0; i < size; i++) numList[i] = 0;// initialize array vars to 0 numList[5] = 20;// bracket notation *(numList + 7) = 15;// pointer-offset notation // means same as numList[7]
22
To deallocate memory that was created with new, we use the unary operator delete. The one operand should be a pointer that stores the address of the space to be deallocated: int * ptr = new int;// dynamically created int //... delete ptr;// deletes space that ptr points to Note that the pointer ptr still exists in this example. That's a named variable subject to scope and extent determined at compile time. It can be reused: ptr = new int[10];// point p to a brand new array To de-allocate a dynamic array, use this form: delete [] name_of_pointer;
23
Example: int * list = new int[40];// dynamic array delete [] list;// de-allocates the array list = 0; // reset list to null pointer After de-allocating space, it's always a good idea to reset the pointer to null unless you are pointing it at another valid target right away. To consider: So what happens if you fail to de- allocate dynamic memory when you are finished with it? (i.e. why is de-allocation important?)
24
If you have an existing array, and you want to make it bigger (add array cells to it), you cannot simply append new cells to the old ones. Arrays are stored in consecutive memory, and you never know whether or not the memory immediately after the array is already allocated for something else. For that reason, the process takes a few more steps. Here is an example using an integer array. Let's say this is the original array: int * list = new int[size];
25
Suppose I want to resize this so that the array called list has space for 5 more numbers (presumably because the old one is full). There are four main steps. ◦ 1. Create an entirely new array of the appropriate type and of the new size. (You'll need another pointer for this). int * temp = new int[size + 5]; ◦ 2. Copy the data from the old array into the new array (keeping them in the same positions). This is easy with a for-loop. for (int i = 0; i < size; i++) temp[i] = list[i];
26
◦ 3. Delete the old array -- you don't need it anymore! delete [] list; // deletes array pointed to by "list" ◦ 4. Change the pointer. You still want the array to be called "list" (its original name), so change the list pointer to the new address. list = temp; That's it! The list array is now 5 larger than the previous one, and it has the same data in it that the original one had. But, now it has room for 5 more items.
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.