720 likes | 806 Views
Another Way to Define A Class - Inheritance. Inheritance Concept. class Rectangle{ private: int width, length; public: void set(int w, int l); int area(); }. Polygon. Rectangle. Triangle. class Polygon { private: int width, length; public:
E N D
Inheritance Concept class Rectangle{ private: int width, length; public: void set(int w, int l); int area(); } Polygon Rectangle Triangle class Polygon { private: int width, length; public: void set(int w, int l); } class Triangle{ private: int width, length; public: void set(int w, int l); int area(); }
Inheritance Concept class Polygon { protected: int width, length; public: void set(int w, int l); } Polygon Rectangle Triangle class Rectangle{ protected: int width, length; public: void set(int w, int l); int area(); } class Rectangle : public Polygon { public:int area(); }
Inheritance Concept class Polygon { protected: int width, length; public: void set(int w, int l); } Polygon Rectangle Triangle class Triangle{ protected: int width, length; public: void set(int w, int l); int area(); } class Triangle : public Polygon { public: int area(); }
Inheritance Concept class Point { protected: int x, y; public: void set(int a, int b); } x y Point Circle 3D-Point x y r x y z class Circle : public Point { private: double r; } class 3D-Point: public Point { private: int z; }
Inheritance Concept • Augmenting the original class • Specializing the original class Polygon Point Rectangle Triangle Circle 3D-Point real imag ComplexNumber RealNumber ImaginaryNumber imag real
Why Inheritance ? Inheritance is a mechanism for • building class types from existing class types • defining new class types to be a • specialization • augmentation of existing types
Define a Class Hierarchy • Syntax: classDerivedClassName : access-levelBaseClassName where • access-level specifies the type of derivation • private by default, or • public • Any class can serve as a base class • Thus a derived class can also be a base class
Class Derivation Point class Point{ protected: int x, y; public: void set(int a, int b); } 3D-Point Sphere class 3D-Point : public Point{ private: double z; … … } class Sphere : public 3D-Point{ private: double r; … … } Point is the base class of 3D-Point, while 3D-Point is the base class of Sphere
What to inherit? • In principle, every member of a base class is inherited by a derived class • just with different access permission
Two levels of access control over class members class definition inheritance type Access Control Over the Members class Point{ protected: int x, y; public: void set(int a, int b); } class Circle : public Point{ … … }
Access Rights of Derived Classes • The type of inheritance defines the minimum access level for the members of derived classthat are inherited from the base class • With public inheritance, the derived class follow the same access permission as in the base class • With protected inheritance, only the public members inherited from the base class can be accessed in the derived class as protected members • With private inheritance, none of the members of base class is accessible by the derived class Type of Inheritance Access Control for Members
Class Derivation class daughter : public mother{ private: double a; public: void foo ( ); } mother daughter son class mother{ protected: int x, y; public: void set(int a, int b); private: int z; } void daughter :: foo ( ){ x = y = 20; set(5, 10); cout<<“value of a ”<<a<<endl; z = 100;//error, a private member } daughter can access 3 of the 4 inherited members
Class Derivation class son : protected mother{ private: double b; public: void foo ( ); } mother daughter son class mother{ protected: int x, y; public: void set(int a, int b); private: int z; } void son :: foo ( ){ x = y = 20; // error, not a public member set(5, 10); cout<<“value of b ”<<b<<endl; z = 100; //error, not a public member } son can access only 1 of the 4 inherited member
What to inherit? • In principle, every member of a base class is inherited by a derived class • just with different access permission • However, there are exceptions for • constructor and destructor • operator=() member • friends Since all these functions are class-specific
Constructor Rules for Derived Classes The default constructor and the destructor of the base class are always called when a new object of a derived class is created or destroyed. class A { public: A ( ) {cout<< “A:default”<<endl;} A (int a) {cout<<“A:parameter”<<endl;} } class B : public A { public: B (int a) {cout<<“B”<<endl;} } output: A:default B B test(1);
Constructor Rules for Derived Classes You can also specify an constructor of the base class other than the default constructor • DerivedClassCon ( derivedClass args ) : BaseClassCon ( baseClass args ) • { DerivedClass constructor body } class A { public: A ( ) {cout<< “A:default”<<endl;} A (int a) {cout<<“A:parameter”<<endl;} } class C : public A { public: C (int a) : A(a) {cout<<“C”<<endl;} } output: A:parameter C C test(1);
Define its Own Members The derived class can also define its own members, in addition to the members inherited from the base class class Point{ protected: int x, y; public: void set(int a, int b); } x y Point x y r Circle protected: int x, y; private: double r; public: void set(int a, int b); void set_r(double c); class Circle : public Point{ private: double r; public: void set_r(double c); }
Even more … • A derived class can override methods defined in its parent class. With overriding, • the method in the subclass has the identical signature to the method in the base class. • a subclass implements its own version of a base class method. class A { protected: int x, y; public: void print () {cout<<“From A”<<endl;} } class B : public A { public: void print () {cout<<“From B”<<endl;} }
Access a Method class Point { protected: int x, y; public: void set(int a, int b) {x=a; y=b;} void foo (); void print(); } class Circle : public Point{ private: double r; public: void set (int a, int b, double c) { Point :: set(a, b); //same name function call r = c; } void print(); } Circle C; C.set(10,10,100); // from class Circle C.foo (); // from base class Point C.print(); // from class Circle Point A; A.set(30,50); // from base class Point A.print(); // from base class Point
Time ExtTime Putting Them Together • Time is the base class • ExtTime is the derived class with public inheritance • The derived class can • inherit all members from the base class, except the constructor • access all public and protected members of the base class • define its private data member • provide its own constructor • define its public member functions • override functions inherited from the base class
classTime Specification // SPECIFICATION FILE ( time.h) class Time { public : void Set (int h,int m, int s ) ; void Increment ( ) ; void Write ( ) const ; Time ( int initH, int initM, int initS ) ; // constructor Time () ; // default constructor protected : int hrs ; int mins ; int secs ; } ;
Class Interface Diagram Timeclass Set Protected data: hrs mins secs Increment Write Time Time
Derived Class ExtTime // SPECIFICATION FILE ( exttime.h) #include “time.h” enum ZoneType {EST, CST, MST, PST, EDT, CDT, MDT, PDT } ; class ExtTime : public Time // Time is the base class and use public inheritance { public : void Set (int h, int m, int s, ZoneType timeZone ) ; void Write ( ) const; //overridden ExtTime (int initH, int initM, int initS, ZoneType initZone ) ; ExtTime (); // default constructor private : ZoneType zone ; // added data member } ;
Class Interface Diagram ExtTimeclass Set Set Protected data: hrs mins secs Increment Increment Write Write ExtTime Time ExtTime Time Private data: zone
Implementation of ExtTime ExtTime :: ExtTime ( ) { zone = EST ; } Default Constructor ExtTime et1; et1 hrs = 0 mins = 0 secs = 0 zone = EST The default constructor of base class, Time(), is automatically called, when an ExtTime object is created.
5000 hrs = 8 mins = 30 secs = 0 zone = EST et2 6000 ??? 5000 Implementation of ExtTime Another Constructor ExtTime :: ExtTime (int initH, int initM, int initS, ZoneType initZone) : Time (initH, initM, initS) // constructor initializer { zone = initZone ; } ExtTime *et2 = new ExtTime(8,30,0,EST);
Implementation of ExtTime void ExtTime :: Set (int h, int m, int s, ZoneType timeZone) { Time :: Set (hours, minutes, seconds); // same name function call zone = timeZone ; } void ExtTime :: Write ( ) const // function overriding { string zoneString[8] = {“EST”, “CST”, MST”, “PST”, “EDT”, “CDT”, “MDT”, “PDT”} ; Time :: Write ( ) ; cout <<‘ ‘<<zoneString[zone]<<endl; }
Working withExtTime #include “exttime.h” … … int main() { ExtTime thisTime ( 8, 35, 0, PST ) ; ExtTime thatTime ; // default constructor called thatTime.Write( ) ; // outputs 00:00:00 EST thatTime.Set (16, 49, 23, CDT) ; thatTime.Write( ) ; // outputs 16:49:23 CDT thisTime.Increment ( ) ; thisTime.Increment ( ) ; thisTime.Write ( ) ; // outputs 08:35:02 PST }
Inheritance Summary • Inheritance is a mechanism for defining new class types to be a specialization or an augmentation of existing types. • In principle, every member of a base class is inherited by a derived class with different access permissions, except for the constructors
More C++ Concepts Operator overloading Friend Function This Operator Inline Function
Review • There are different types of member functions in the definition of a class • Accessor • int Str :: get_length(); • implementor/worker • void Rectangle :: set(int, int); • helper • void Date :: errmsg(const char* msg); • constructor • Account :: Account(); • Account :: Account(const Account& a); • Account :: Account(const char *person); • destructor • Account :: ~Account();
Operator overloading • Programmer can use some operator symbols to define special member functions of a class • Provides convenient notations for object behaviors
Why Operator Overloading int i, j, k; // integers float m, n, p; // floats k = i + j; // integer addition and assignment p = m + n; // floating addition and assignment The compiler overloads the + operator for built-in integer and float types by default, producing integer addition with i+j, and floating addition with m+n. We can make object operation look like individual int variable operation, using operator functions Date a,b,c; c = a + b;
Operator Overloading Syntax • Syntax is: Examples: operator+ operator- operator* operator/ operator@(argument-list) --- operator is a function --- @ is one of C++ operator symbols (+, -, =, etc..)
Example of Operator Overloading class CStr { char *pData; int nLength; public: // … void cat(char *s); // … friend CStr operator+(CStr str1, CStr str2); friend CStr operator+(CStr str, char *s); friend CStr operator+(char *s, CStr str); //accessors char* get_Data(); int get_Len(); }; void CStr::cat(char *s) { int n; char *pTemp; n=strlen(s); if (n==0) return; pTemp=new char[n+nLength+1]; if (pData) strcpy(pTemp,pData); strcat(pTemp,s); pData=pTemp; nLength+=n; }
The Addition (+) Operator CStr operator+(CStr str1, CStr str2) { CStr new_string(str1); //call the copy constructor to initialize an entirely new CStr object with the first operand new_string.cat(str2.get_Data()); //concatenate the second operand onto the end of new_string return new_string; //call copy constructor to create a copy of the return value new_string } new_string str1 strlen(str1) strcat(str1,str2) strlen(str1)+strlen(str2)
How does it work? CStr first(“John”); CStr last(“Johnson”); CStr name(first+last); CStr operator+(CStr str1,CStr str2) { CStr new_string(str1); new_string.cat(str2.get()); return new_string; } “John Johnson” name Copy constructor Temporary CStr object
Implementing Operator Overloading • Two ways: • Implemented as member functions • Implemented as non-member or Friend functions • the operator function may need to be declared as a friend if it requires access to protected or private data • Expression obj1@obj2 translates into a function call • obj1.operator@(obj2), if this function is defined within class obj1 • operator@(obj1,obj2), if this function is defined outside the class obj1
c = a.operator+ (b); Implementing Operator Overloading • Defined as a member function class Complex { ... public: ... Complex operator +(const Complex &op) { double real = _real + op._real, imag = _imag + op._imag; return(Complex(real, imag)); } ... }; c = a+b;
c = operator+ (a, b); Implementing Operator Overloading • Defined as a non-member function class Complex { ... public: ... double real() { return _real; } //need access functions double imag() { return _imag; } ... }; c = a+b; Complex operator +(Complex &op1, Complex &op2) { double real = op1.real() + op2.real(), imag = op1.imag() + op2.imag(); return(Complex(real, imag)); }
c = operator+ (a, b); Implementing Operator Overloading • Defined as a friend function class Complex { ... public: ... friend Complex operator +( const Complex &, const Complex & ); ... }; c = a+b; Complex operator +(Complex &op1, Complex &op2) { double real = op1._real + op2._real, imag = op1._imag + op2._imag; return(Complex(real, imag)); }
What is ‘Friend’? • Friend declarations introduce extra coupling between classes • Once an object is declared as a friend, it has access to all non-public members as if they were public • Access is unidirectional • If B is designated as friend of A, B can access A’s non-public members; A cannot access B’s • A friend function of a class is defined outside of that class's scope
More about ‘Friend’ • The major use of friends is • to provide more efficient access to data members than the function call • to accommodate operator functions with easy access to private data members • Friends can have access to everything, which defeats data hiding, so use them carefully • Friends have permission to change the internal state from outside the class. Always recommend use member functions instead of friends to change state
Assignment Operator • Assignment between objects of the same type is always supported • the compiler supplies a hidden assignment function if you don’t write your own one • same problem as with the copy constructor - the member by member copying • Syntax: class& class::operator=(const class &arg) { //… }
Return type - a reference to (address of) a CStr object Argument type - a reference to a CStr object (since it is const, the function cannot modify it) Assignment function is called as a member function of the left operand =>Return the object itself str1=str2; str1.operator=(str2) Example: Assignment for CStr class Assignment operator for CStr: CStr& operator=(const CStr & source) CStr& operator=(const CStr &source){ //... Do the copying return *this; }
ostream& operator<<(ostream &os, const Date &d) { os<<d.month<<“/”<<d.day<<“/”<<d.year; return os; } … cout<< d1; //overloaded operator ostream& operator<<(ostream &os, const Date &d) { os<<d.month<<“/”<<d.day<<“/”<<d.year; return os; } … cout<< d1; //overloaded operator cout ---- object of ostream cout ---- object of ostream Overloading stream-insertion and stream-extraction operators • In fact, cout<< or cin>> are operator overloading built in C++ standard lib of iostream.h, using operator "<<" and ">>" • cout and cin are the objects of ostream and istream classes, respectively • We can add a friend function which overloads the operator << friend ostream& operator<< (ostream &ous, const Date &d);
cin ---- object of istream Overloading stream-insertion and stream-extraction operators • We can also add a friend function which overloads the operator >> friend istream& operator>> (istream &in, Date &d); istream& operator>> (istream &in, Date &d) { char mmddyy[9]; in >> mmddyy; // check if valid data entered if (d.set(mmddyy)) return in; cout<< "Invalid date format: "<<d<<endl; exit(-1); } cin >> d1;
The “this” pointer • Within a member function, the this keyword is a pointer to the current object, i.e. the object through which the function was called • C++ passes a hiddenthis pointer whenever a member function is called • Within a member function definition, there is an implicit use of this pointer for references to data members this Data member reference Equivalent to pData this->pData nLength this->nLength pData nLength CStr object (*this)
Inline functions • An inline function is one in which the function code replaces the function call directly. • Inline class member functions • if they are defined as part of the class definition, implicit • if they are defined outside of the class definition, explicit, I.e.using the keyword, inline. • Inline functions should be short (preferable one-liners). • Why? Because the use of inline function results in duplication of the code of the function for each invocation of the inline function