Lecture 10: Introduction to Inheritance CS427: Programming in C++ Lecture 10.2 11am, 12th March 2012 CS427 Lecture 10: Introduction to Inheritance 1/17
In today s class 1 Inheritance protected 2 Replacing members 3 virtual CS427 Lecture 10: Introduction to Inheritance 2/17
Inheritance The final new idea we ll introduce in C++ is the notion of Inheritance. Basic concept Given a class, construct from it a new class that has the properties of the original class, plus some new ones. The original class is called the base, parent or super class. The new one, is called the derived, child or sub class. The derived class will inherit All the data members of the base class, though it may not be able to access them directly, The ordinary function members, but not constructors, destructors, or assignment operators. CS427 Lecture 10: Introduction to Inheritance 3/17
Inheritance Some programming/syntax aspects: The syntax for defining a derived class class Derived : public Base Here public means that was public to the base class is publicly accessible to the derived class. (This is the most typical case.) class Derived : private Base Here private means everything remains private to the base class, and so can t be access by the derived class. (Not very useful). To added to the public and private specifiers, we ll add protected virtual functions CS427 Lecture 10: Introduction to Inheritance 4/17
Inheritance In our first example, 01InheritExample.cpp link!, we construct a simple base class that has a single data member. We ll then make a derived class. Notice that, although the derived class inherits the base class s private datum, it must use the access method SetX() to change it, and GetX() to evaluate it. CS427 Lecture 10: Introduction to Inheritance 5/17
Inheritance class Point { private : i n t x ; public : Point ( i n t X=0) { x=x ; } ; i n t GetX ( void ) { return ( x ) ; } ; void SetX ( i n t X) { x=x ; } ; } ; class TwoPoint : public Point { private : i n t y ; public : TwoPoint ( i n t X=0, i n t Y=0) { SetX (X ) ; y=y ; } ; i n t GetY ( void ) { return ( y ) ; } ; void SetY ( i n t Y) { y=y ; } ; void PrintXY ( void ) ; } ; void TwoPoint : : PrintXY ( void ) { cout << ( << GetX ( ) <<, << y << ) \ n ; } CS427 Lecture 10: Introduction to Inheritance 6/17
Inheritance protected To date, we designated the accessibility every data member and member function of a class with one of the following access specifiers: private: This specifies that the data/function member can only be accessed from within the class. For data members, this means that the data can be accessed or modified by a function that is a member or friend of the class. Similarly, private functions can be called by another member/friend function of the class. This is the default. OR public: specifies that a data or function member can be accessed from anywhere in your code. Now we add: protected:. These members act the same as private ones, except that they are directly accessible within a derived class. Compare the following, 02Protected.cpp link!, with our earlier example. CS427 Lecture 10: Introduction to Inheritance 7/17
Inheritance class Point { protected : / / this was private in 01Inherit i n t x ; public : Point ( i n t X=0) { x=x ; } ; i n t GetX ( void ) { return ( x ) ; } ; void SetX ( i n t X) { x=x ; } ; } ; protected class TwoPoint : public Point { private : i n t y ; public : / / Don t have to use SetX in the constructor TwoPoint ( i n t X=0, i n t Y=0) { x=x ; y=y ; } ; i n t GetY ( void ) { return ( y ) ; } ; void SetY ( i n t Y) { y=y ; } ; void PrintXY ( void ) ; } ; void TwoPoint : : PrintXY ( void ) { / / Don t have to use GetX cout << ( << x <<, << y << ) \ n ; } CS427 Lecture 10: Introduction to Inheritance 8/17
Replacing members Suppose, for example, that a base class has a method void PrintData(void). It is possible to make a derived class that also contains a (new) method call void PrintData(void). The version of PrintData(void) from the derived class will superceed the one from the base class. However, the original one does not disappear, it can still be called, but you need to use the base class name and scope resolution operator. Note: If the base and derived classes have functions with the same names, but different signatures, then the function is overloaded, not replaced. CS427 Lecture 10: Introduction to Inheritance 9/17
Replacing members 03Replacement.cpp link! class Point { protected : i n t x ; public : Point ( i n t X=0) { x=x ; } ; i n t GetX ( void ) { return ( x ) ; } ; void SetX ( i n t X) { x=x ; } ; void PrintData ( void ) ; } ; void Point : : PrintData ( void ) { cout << ( << x << ) \ n ; } CS427 Lecture 10: Introduction to Inheritance 10/17
Replacing members class TwoPoint : public P o i n t { private : i n t y ; public : TwoPoint ( i n t X=0, i n t Y=0) { x=x ; y=y ; } ; i n t GetY ( void ) { return ( y ) ; } ; void SetY ( i n t Y) { y=y ; } ; void PrintData ( void ) ; } ; void TwoPoint : : PrintData ( void ) { cout << ( << x <<, << y << ) \ n ; } CS427 Lecture 10: Introduction to Inheritance 11/17
Replacing members i n t main ( void ) { Point b ; TwoPoint d ; b. SetX ( 1 2 ) ; cout << b= ; b. PrintData ( ) ; d. SetX ( 1 ) ; d. SetY ( 2 ) ; cout << \nd= ; d. PrintData ( ) ; } cout << C a l l i n g the Point version of P r i n t Data : ; cout << d= ; d. Point : : PrintData ( ) ; return ( 0 ) ; CS427 Lecture 10: Introduction to Inheritance 12/17
virtual There are other times when we need to take care which of two functions that have the same signature and belonging the base and derived class is called. In particular, consider the following code segment: Point d, b ; b = new Point ( 3 ) ; d = new TwoPoint ( 5, 6 ) ; Here b and d are both pointers to the type Point, but created using dynamically memory allocation. In particular, d in initialised as an instance of the TwoPoint class. But, if we call (*d).printdata() (or, equivalently, d->printdata() it is base::printdata() that is called. If we want Derived::PrintData() to be called, then in the definition of Point, we put virtual before the definition of PrintData(). This is shown in 04Virtual.cpp link! CS427 Lecture 10: Introduction to Inheritance 13/17
virtual As a more natural example of when a virtual function might be required, consider the following implementation for items stored in a library. Items in the library all have, at the least, a title and a call-number. The base class item includes private members string title and int CallNumber. There are methods that print the title and call number, and a method printrecord that does both. class item { protected : s t r i n g t i t l e ; i n t CallNumber ; public : item ( s t r i n g t =, i n t n=0) { t i t l e = t ; CallNumber=n ; } ; void s e t T i t l e ( s t r i n g t ) { t i t l e = t ; } ; void setcallnumber ( i n t n ) { CallNumber=n ; } ; void p r i n t T i t l e ( void ) { cout << t i t l e ; } ; void printcall Number ( void ) { cout << CallNumber ; } ; void printrecord ( void ) ; } ; CS427 Lecture 10: Introduction to Inheritance 14/17
virtual The code for the printrecord method is: void item : : printrecord ( void ) { cout << t i t l e : ; p r i n t T i t l e ( ) ; cout << ( c a l l number : ; printcallnumber ( ) ; cout << ) << endl ; } CS427 Lecture 10: Introduction to Inheritance 15/17
virtual Next we have a derived class specifically for books. It has a different form of call number in this case, based on the Dewey Decimal system. Each book s call number is made up of two integers. The first represents the broad category (e.g., 005=Computer programming) and the second the specific subject (e.g., 100=Software Engineering). class Book : public item { private : i n t Category ; i n t Subject ; public : Book ( s t r i n g t =, i n t c =0, i n t s =0) { t i t l e = t ; Category=c ; Subject=s ; } ; void setcallnumber ( i n t c, i n t s ) { Category=c ; Subject=s ; } ; void printcal lnumber ( void ) ; } ; void Book : : printcall Number ( void ) { cout << s e t f i l l ( 0 ) << setw ( 3 ) << Category <<. << Subject ; } CS427 Lecture 10: Introduction to Inheritance 16/17
virtual So if we declare an object of type book, and call its method printrecord. But printrecord was inherited from the base class. That is, book::printrecord is the same as item::printrecord. So it will call item::printcallnumber. That is not what we intended. If we change the definition of item::printcallnumber in the base class to specify that it is virtual, then the binding that is done at compile time is changed, and even though printrecord is inherited from item, we ll find that book::printrecord will call book::printcallnumber. The full example is given in 05Library.cpp link! CS427 Lecture 10: Introduction to Inheritance 17/17