280 likes | 383 Views
EC-241 Object Oriented Programming. LECTURE 4. Composition. Definition: A data member of a class is an object of some other class Example: an AlarmClock object needs to know when it is supposed to sound its alarm, so why not include a Time object as a member of the AlarmClock class?
E N D
EC-241 Object Oriented Programming LECTURE 4
Composition • Definition: A data member of a class is an object of some other class • Example: an AlarmClock object needs to know when it is supposed to sound its alarm, so why not include a Time object as a member of the AlarmClock class? • Referred to as has-arelationship • reusability
//Date.h #ifndef DATE_H #define DATE_H class Date { public: Date(int=1, int=1, int=1900); void print() const; ~Date(); private: int month; //1-12 int day; //1-31 based on month int year; //utility function to check if day is proper for month and year intcheckDay(int) const; };
//Date.cpp #include "date.h" #include <iostream> using namespace std; Date:: Date(int mn, int dy, int yr) { if (mn>0 && mn<=12) month=mn; else { month=1; cout<<"invalid month; set to 1\n"; } year =yr; day =checkDay(dy); cout<<"Date object constructor for date " ;print(); cout<<endl; } void Date::print() const { cout<<month<<'/'<<day<<'/'<<year; }
Date::~Date() { cout<<"Date object destructor for date "; print(); cout<<endl; } int Date::checkDay(inttestDay) const { const intdaysPerMonth[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; if (testDay >0 && testDay<=daysPerMonth[month]) return testDay; if (month==2 && testDay==29 && (year%400==0 || (year%4==0 && year%100!=0))) return testDay; cout<<"invalid Day; set to 1\n"; return 1; }
//Employee.h #ifndef EMPLOYEE_H #define EMPLOYEE_H #include "d:\projects\composition\Date.h" #include <iostream> using namespace std; class Employee { char firstName[25]; char lastName[25]; const Date birthDate; //composition: member object const Date hireDate; //composition: member object public: Employee(const char * const, const char * const, const Date &, const Date &); void print() const; ~Employee(); }; #endif
//Employee.cpp #include "d:\projects\composition\Date.h" #include "d:\projects\composition\Employee.h" //ctor uses member initializer list to pass initializer //values to ctors of member objects //Note: this invokes the default copy ctor Employee::Employee(const char * const first, const char * const last, const Date & dateOfBirth, const Date & dateOfHire) :birthDate(dateOfBirth), hireDate(dateOfHire) { int length=(int)strlen(first); length=(length<25 ? length:24); strncpy(firstName, first, length); firstName[length]=‘\0'; length=(int)strlen(last); length=(length<25 ? length:24); strncpy(lastName, last, length); lastName[length]=‘\0'; cout<<"Employee object ctor: "<<firstName<<' ' <<lastName; }
void Employee::print() const { cout<<lastName<<", "<<firstName<<" Hired: "; hireDate.print(); cout<<" Birthday: "; birthDate.print(); cout<<endl; }
Employee::~Employee() { cout<<" Employee object destructor: " <<lastName<<", " <<firstName<<endl; }
//test.cpp #include "Employee.h" void main() { Date birth(7, 24, 1949); Date hire(3, 12, 1988); Employee manager("Bob", "Blue", birth, hire); cout<<endl; manager.print(); }
Order of Constructor and Destructor for Composition • Member objects are constructed in the order in which they are declared in the class definition (not in the order they are listed in the constructor’s member initializer list) and before their enclosing class objects are constructed • Member objects are constructed from the inside out and destroyed in the reverse order
Compilation error occurs if a member object is not initialized with a member initializer and the member object’s class doest not provide a default constructor • Initialize member objects explicitly through member intializers. This eliminates the overhead of doubly initializing
#include <iostream> using namespace std; class Point { intx,y; public: Point(): x(0), y(0) {cout<<"ctor for point: "<<x<<' '<<y<<endl;} void get() const { cout<<x<<' '<<y<<endl; } void set(int a, int b) { x=a; y=b; } ~Point() {cout<<"dtor for point: "<<x<<' '<<y<<endl;} };
class Circle { Point center; //COMPOSITION int radius; public: Circle(): radius(0) {cout<<"ctor for circle: "; center.get(); cout<<' '<<radius<<endl;} ~Circle() {cout<<"dtor for circle: "; center.get(); cout<<' '<<radius<<endl;} };
void main() { Circle c; }
Friendship • Friends of a class are not members of the class, yet can access the non-public members of the class • A class can have two types of friends • Friend functions • Friend classes
Friendship • Friendship is granted, not taken-i.e. for class B to be a friend of class A, class A must explicitly declare that class B is its friend. • Friendship is not symmetric. For example, if class A is a friend of class B, this does not necessarily mean that class B is also a friend of class A. • Friendship is not transitive. For example if class A is a friend of class B and class B is a friend of class C, we cannot infer that class A is a friend of class C.
Friend Functions • To declare a function as friend of a class, precede the function prototype in the class definition with keyword friend. • Member access notions of private, public etc. are not relevant to friend declaration, so friend declarations can be placed anywhere in a class definition. • As a good programming practice, place all friendship declarations first inside the class definition’s body and do not precede them with any access specifier
Friend Function Example class Count { friend void setX(Count &, int); public: Count(): x(0) {} void print() const {cout<<x<<endl;} private: int x; };
Friend Function Example void setX(Count & c, intval) {c.x=val; } void main() { Count counter; counter.print(); setX(counter, 8); counter.print(); }
Friend Class Example #include <iostream> using namespace std; class A { friend class B; int x; public: A(): x(0){} int get() const { return x; } void set(int y) { x=y; } };
Friend Class Example class B { int z; public: void set(A & a) { a.x=20; } int get() const { return z; } };
Friend Class Example void main() { A a1; B b1; b1.set(a1); cout<<a1.get()<<endl; }
static Data Members • Normally, each object maintains its own copy of data members. • However, if some data item in a class is declared static, only one such item is created for the entire class, no matter how many objects are there. • A static data item is useful when all objects of the same class must share a common item of information.
static Data Members • A static data member exists even if there are no objects of the class instantiated. • Static class member data is used to share information among the objects of a class.
class foo { private: static int count; //only one data item for all objects //Note: declaration only public: foo() {count++; } //increments count when object created intgetcount() {return count; } }; intfoo::count=0; void main() { foo f1, f2, f3; cout<<f1.getcount()<<f2.getcount()<<f3.getcount(); //each object sees the same value }