Aggregation / Composition Andy Wang Object Oriented Programming in C++ COP 3330 Aggregation is a relationship between objects Embed an object (or a pointer) of one class type as member data of another class type Object as Class Members Composition refers to a stronger form of aggregation Embedded objects would typically not exist independent of the container object
Is also known as the has a relationship Engine object inside a Car object as member data 52 Card objects as member data of class Deck Promotes the idea of tool building Objects of a class can be used as components inside other classes http://www.cs.fsu.edu/~myers/cop3330/ examples/timer/ Timer class Example Directory content timer.h // declarations for Display and
Timer // classes tmer.cpp // implementations for both classes main.cpp // driver program timer.h class Display { public: Display(int lim); void increment(); // add 1 to value bool setValue(int val); int getLimit() const; int getValue() const; void show() const; private: const int LIMIT; // max value
int value; // 0 .. limit 1 }; timer.h class Timer { public: Timer(); Timer(int h, int m); void increment() // Add 1 min bool set(int h, int m); void show() const; Timer add(const Timer &t) const; private: Display hours, minutes; }; The Timer object has two Display objects #include
#include timer.h using namespace std; timer.cpp Display::Display(int lim) : LIMIT(lim) { value = 0; } void Display::increment() { value = (value + 1) % LIMIT; } bool Display::setValue(int val) { if (val < 0 || value >= LIMIT) return false; value = val; return true; } int Display::getValue() const { return value; } int Display::getLimit() const { return LIMIT; } void Display::show() const {
// pad with a leading zero, if needed if (value < 10) cout << 0; cout << value; } timer.cpp Timer::Timer() : hours(24), minutes(60) { } Timer::Timer(int h, int m) : hours(24), minutes(60) { if (set(h, m) == false) set (0, 0); } void Timer::increment() { minutes.increment(); if (minutes.getValue() == 0) hours.increment(); } bool Timer::set(int h, int m) { if (h < 0 || h >= hours.getLimit() || m < 0 || m >= minutes.getLimit())
return false; hours.setValue(h); minutes.setValue(m); return true; } void Timer::show() const { hours.show(); cout << : << minutes.show(); } timer.cpp Timer Timer::add(const Timer &t) const { int h = hours.getValue() + t.hours.getValue(); int m = minutes.getValue() + t.minutes.getValue(); if (m >= minutes.getLimit()) { m = m minutes.getLimit(); h = h + 1;
} if (h >= hours.getLimit()) h = h hours.getLimit(); return Timer(h, m); // build and return // result object } #include #include timer.h using namespace std; void timerInput(Timer &t, const char *label) { int h, m; bool success; main.cpp do {
cout << Enter hours for << label << timer: ; cin >> h; cout << Enter minutes for << label << timer: ; cin >> m; success = t.set(h, m); if (!success) cout << Invalid timer values. Try again. \n; } while (!success) cout << \n; } main.cpp void tick(Timer &t, const char *which, int howMany) { cout << Incrementing << which << timer by << howMany << minutes\n;
cout << Initial timer value = ; t.show(); cout << \n; for (int i = 0; i < howMany; i++) { t.increment(); t.show(); cout << \n; } } void showTimers(const Time& t1, const Time &t2) { cout << t1 = ; t1.show(); cout << \ n; cout << t2 = ; t2.show(); cout << \ n; } int main() { Timer t1, t2(12, 57); cout << Here are the initial values of the timers: \n;
showTimers(t1, t2); timerInput(t1, first); timerInput(t2, second); showTimers(t1, t2); main.cpp cout << The two timers added together = ; t1.Add(t2).show(); cout << \n\n; int num; cout << How many minutes should we advance the timers? ; cin >> num; tick(t1, first, num); tick(t2, second, num); return 0; } Pay attention to the context
Side Comments The user of the Timer is the main program The user of the Display objects is the Timer object Timer object will call Display functions through objects (hours and minutes) Constructo rs for Embedded Objects When an object is created, its construct runs and also invokes the constructors of its embedded objects If nothing is done, it will invoke the default constructor Use initialization list to invoke a
constructor with parameters for an embedded object Normal creation of Display objects Constructo rs for Embedded Objects Creation of Display objects within the Timer Constructor Initialization cannot be performed in the class declaration Display hours(24);
Display minutes(60); Need to use initialization list Display has no default constructor Timer::Timer() : hours(24), minutes(60) { } http://www.cs.fsu.edu/~myers/cop3330/ examples/machine/ Another Example: Soda
Machine class Directory content machine.h // declarations for CoinCounter, // Dispenser, and SodaMachine classes machine.cpp // implementations for these classes menu.cpp // driver program machine.h class CoinCounter { public: CoinCounter(int initial = 100); int CurrentAmount(); void AcceptCoin(int amt); void TakeAll();
void DispenseChange(int amt); private: int amount; // tendered so far int available; // for changes }; class Dispenser { public: Dispenser(int num = 24); bool HandleButton(); private: int numCans; }; machine.h class SodaMachine { public: SodaMachine(); void DoCommand(char cmd);
private: CoinCounter counter; Dispenser cola, lite, root, orange, free; int price; void DoCoin(char cmd); void DoSelection(char cmd); }; #include #include machine.h using namespace std; machine.c pp CoinCounter::CoinCounter(int initial) { amount = 0; available = initial; } int CoinCounter::CurrentAmount() { return
amount; } void CoinCounter::AcceptCoin(int amt) { amount += amt; } void CoinCounter::TakeAll() { available += amount; amount = 0; } machine.c pp void CoinCounter::DispenseChange(int amt) { if (available >= amt) { cout << \n*** Change returned: << amt; available -= amt; } else cout << \n*** EXACT CHANGE ONLY from now on;
} Dispenser::Dispenser(int num) { numCans = num; } bool Dispenser::HandleButton() { if (numCans == 0) return false; numCan--; return true; } machine.c pp // initialize a SodaMachine and its CoinCounter and // Dispenser objects SodaMachine::SodaMachine() { price = 75; } void SodaMachine::DoCommand(char cmd) { if ((cmd == Q) || (cmd == D) || (cmd
== N) || (cmd == R)) DoCoin(cmd); else DoSelection(cmd); } machine.c pp void SodaMachine::DoCoin(char cmd) { int amt; switch(cmd) { case R: amt = counter.CurrentAmount(); counter.TakeAll(); counter.DispenseChange(amt); break; case Q: counter.AcceptCoin(25); break;
case D: counter.AcceptCoin(10); break; case N: counter.AcceptCoin(5); break; } } int tendered = counter.CurrentAmount(); bool success; machine.c pp if (tendered < price) cout << \n*** Insert more money; else { switch(cmd) { case C: success = cola.HandleButton(); break;
case L: success = lite.HandleButton(); break; case B: success = root.HandleButton(); break; case O: success = orange.HandleButton(); break; case F: success = free.HandleButton(); break; if (success) { cout << \n*** Sale complete; counter.TakeAll(); if (tendered > price) machine.c
pp counter.DispenseChange(tender price); } else cout << \n*** MAKE ANOTHER SELECTION for this from now on; } } #include #include // for toupper #include machine.h using namespace std; menu.cpp Int IsLegel(char cmd) { return ((cmd == Q) || (cmd == D) ||
(cmd == N) || (cmd == R) || (cmd == C) || (cmd == L) || (cmd == B) || (cmd == O) || (cmd == F) || (cmd == X) || (cmd == M)); } char GetCommand() { char cmd; menu.cpp do { cout << \n> ; cin >> cmd; cmd = toupper(cmd); if (!IsLegal(cmd)) cout << \n*** Unrecognized commend. Type M to see the menu.; } while (!IsLegal(cmd));
return cmd; } menu.cpp void ShowMenu() { cout << "Please select one of the following options\n"; cout << "by pressing the indicated key:\n"; cout << "\n\tMoney-handling\n"; cout << "\t\tQ: Quarter\n"; cout << "\t\tD: Dime\n"; cout << "\t\tN: Nickel\n"; cout << "\t\tR: Return all coins\n"; cout << "\n\tDrink selection ($0.75 each)\n"; cout << "\t\tC: Cola\n"; cout << "\t\tL: Lite cola\n"; cout << "\t\tB: root Beer\n";
cout << "\t\tO: Orange\n"; cout << "\t\tF: caffeine-Free, diet, clear, new-age cola\n"; cout << "\n\tSimulation control\n"; cout << "\t\tM: show this Menu\n"; cout << "\t\tX: eXit the program\n"; } int main() { SodaMachine theMachine; ShowMenu(); char cmd; do { cmd = GetCommand(); if (cmd == M) ShowMenu(); else if (cmd != X) theMachine.DoCommand(cmd); } while (cmd != X); menu.cpp
}