<<

90 Code Reuse by Inheritance C++ allows code reuse by defining new classes called derived classes by inheriting members of one or more classes

n Derived classes may modify inherited behavior and may define its own special data and function

n Inheritance represents an IS-A relationship

n Advantages of inheritance include - Software reuse: Group together common features in a base class - Easy to extend: New derived classes do not affect existing implementation and clients using base classes continue to work for all derived classes

91 A --Cylinder class hierarchy w A Point object can be specified by giving its position (coordinates)

w A Circle object can be specified by giving its position (coordinates) and a

w A Cylinder object can be specified by giving its position, a radius, and a height 92 The Point Class #ifndef POINT_H #define POINT_H #include using std::ostream; class Point { public: explicit Point( int = 0, int = 0 ); // default constructor void setPoint( int, int ); // set coordinates int getX() const { return x; } // get x coordinate int getY() const { return y; } // get y coordinate void print(ostream &) const; // print the point object protected: // accessible to derived classes int x, y; // coordinates of the point }; //Nonmember overloaded output operator ostream &operator<<( ostream &, const Point & ); #endif 93 Meanings of the Inheritance Types w Public

n public (protected)} members of the base class become

n public (protected) members of the derived class

w Protected

n Both public and protected members of the base class become protected members of the derived class

w Private

n Both public and protected members of the base class become private members of the derived class 94 The Circle Class #ifndef CIRCLE_H #define CIRCLE_H #include "point.h" class Circle : public Point { public: explicit Circle(double r = 0.0):radius(r){}; // default constructor Circle( int x, int y, double r = 0.0); void setRadius( double ); // set radius double getRadius() const; // return radius double () const; // calculate area void print(ostream &) const;// print the circle protected: // accessible to derived classes double radius; // radius of the Circle }; ostream &operator<<( ostream &, const Circle & ); #endif 95 The Point class Implementation

1 // Constructor for class Point Point::Point( int a, int b ) { setPoint( a, b ); } // Set the x and y coordinates void Point::setPoint( int a, int b ) { x = a; y = b; }

void Point::print(ostream& ostr) const { ostr << '[' << x << ", " << y << ']' ; }

// Overloaded insertion ostream& operator<<( ostream &ostr, const Point &p ){ p.print(ostr); return ostr; // enables cascading } 96 The Circle class Implementation const double Pi = 3.14159; // Constructor for Circle calls constructor for Point // with a member initializer and initializes radius

Circle::Circle( double r, int a, int b ) : Point( a, b ){ // call base-class constructor setRadius( r ); } // Set radius void Circle::setRadius( double r ) { radius = ( r >= 0 ? r : 0 ); } // Get radius double Circle::getRadius() const { return radius; } 97 The Circle class Implementation // Calculate the double Circle::area() const { return Pi * radius * radius; } // Output a circle in the form: // Center = [x, y]; Radius = void Circle::print(ostream & ostr) const { ostr << "Center = " ; Point::print(ostr); ostr << "; Radius = " << setiosflags( ios::fixed | ios::showpoint ) << setprecision( 2 ) << radius; } ostream& operator<<( ostream &ostr, const Circle &c ) { c.print(ostr); return ostr; // enables cascaded calls } 98 Properties of Derived Class Members Derived class members

n cannot directly access private data members of the base class n if a base class function f() is redefined, the base version is referred to by baseClass::f()

n the constructor, destructor, and assignment operators of a derived class should call, respectively, the constructor (as an initializer), destructor, and assignment operator of the base class

n a friend of a base class is not automatically a friend of a derived class

n redefining inherited function is not overloading: w with a base object, the base version is called w with a derived object, the derived version is called 99 Type Conversion w Every object of a derived class is also an object of base class

w Assigning a derived object to a base object causes slicing, i.e., only base portion is copied

w Assigning a derived-class pointer to a base-class pointer is always valid

2 w Assigning a base-class pointer to a derived-class pointer is dangerous, and requires an explicit casting derivedTypePtr = static_cast baseTypePtr;

w The type conversion rules apply to assignment, and parameter passing 100 The Cylinder Class class Cylinder : public Circle {

public: explicit Cylinder( double h = 0.0): height(h){}; Cylinder( double h, double r, int x, int y); void setHeight( double ); // set height double getHeight() const; // return height double area() const; // calculate and return area double () const; // calculate and return volume void print(ostream &) const;// print the Cylinder protected: double height; // height of the Cylinder }; ostream &operator<<( ostream &, const Cylinder & ); 101 The Cylinder Class Implementation #include "cylinder.h" const double Pi = 3.14159; // Cylinder constructor calls Circle constructor Cylinder::Cylinder( double h, double r, int x, int y ) : Circle( r, x, y )// call base-class constructor { setHeight( h ); } // Set height of Cylinder void Cylinder::setHeight ( double h ){ height = ( h >= 0 ? h : 0 ); } // Get height of Cylinder double Cylinder:: getHeight() const { return height; } // Calculate the area of Cylinder (i.e., area) double Cylinder::area() const { return 2 * Circle::area() + 2 * Pi * radius * height; }

// Calculate volume of Cylinder double Cylinder::volume() const { return Circle::area() * height; }

// print the cylinder object

void Cylinder::print(ostream &ostr ) const { Circle::print(ostr ); ostr << "; Height = " << height;}

// Output Cylinder ostream &operator<<( ostream &ostr , const Cylinder &c ) { c.print(ostr); return ostr; // enables cascaded calls } 102 The Cylinder Class Implementation

// Calculate volume of Cylinder double Cylinder::volume() const { return Circle::area() * height; } // print the cylinder object void Cylinder::print(ostream &ostr ) const { Circle::print(ostr ); ostr << "; Height = " << height; } // Output Cylinder dimensions ostream &operator<<( ostream &ostr , const Cylinder &c ) {

3 c.print(ostr); return ostr; // enables cascaded calls } 103 Testing the Point-Circle-Cylinder Hierarchy Circle c( 2.5, 37, 43 );

// You can call base (Point) class public member // functions via the derived class Circle object c

cout << "X coordinate is " << c.getX() // Point's getX() and getY() << "\nY coordinate is " << c.getY() // are inherited << "\nRadius is " << c.getRadius(); c.setRadius( 4.25 ); c.setPoint( 2, 2 ); // Use inherited setPoint() cout << "\n\nThe new location and radius of c are\n" << c << "\nArea " << c.area() << '\n';

104 Testing the Point-Circle-Cylinder Hierarchy

Point p1 = c; //Slicing: Copy construct p1 using the Point part of c cout << "\nCircle printed as a Point is: " << p1 << endl; Point *pPtr = &c; // Can only refer to the "Point part" of c cout << "\nCircle printed as a Point is: " << *pPtr << endl; Circle* cPtr = &c; cout << "\nCircle printed via a pointer: " << *cPtr << endl; // create a Cylinder object Cylinder cyl( 5.7, 2.5, 12, 23 );

// use get functions to display the Cylinder cout << "X coordinate is " << cyl.getX() << "\nY coordinate is " << cyl.getY() << "\nRadius is " << cyl.getRadius() << "\nHeight is " << cyl.getHeight() << "\n\n";

// use set functions to change the Cylinder's attributes cyl.setHeight( 10 ); cyl.setRadius( 4.25 ); cyl.setPoint( 2, 2 ); cout << "The new location, radius, and height of cyl are:\n" << cyl << '\n';

// display the Cylinder as a Point Point &pRef1 = cyl; // pRef1 "thinks" that cyl is a Point cout << "\nCylinder printed as a Point is: " << pRef1 << "\n\n";

// display the Cylinder as a Circle Circle &circleRef = cyl; // circleRef thinks that cyl is a Circle cout << "Cylinder printed as a Circle is:\n" << circleRef << "\nArea: " << circleRef.area() << endl;

return 0; }

Test run:

X coordinate is 10 Y coordinate is 37 Radius is 43

The new location and radius of c are Center = [2, 2]; Radius = 4.25 Area 56.74

4 Circle printed as a Point is: [2, 2]

Circle printed as a Point is: [2, 2]

Circle printed via a pointer: Center = [2, 2]; Radius = 4.25

The new location, radius, and height of cyl are: Center = [2, 2]; Radius = 4.25; Height = 10.00

Cylinder printed as a Point is: [2, 2]

Cylinder printed as a Circle is: Center = [2, 2]; Radius = 4.25 Area: 56.74 105 Testing the Point-Circle-Cylinder Hierarchy

Point p1 = c; //Slicing: Copy construct p1 using the Point part of c cout << "\nCircle printed as a Point is: " << p1 << endl; Point *pPtr = &c; // Can only refer to the "Point part" of c cout << "\nCircle printed as a Point is: " << *pPtr << endl; Circle* cPtr = &c; cout << "\nCircle printed via a pointer: " << *cPtr << endl; // create a Cylinder object Cylinder cyl( 5.7, 2.5, 12, 23 );

// use get functions to display the Cylinder cout << "X coordinate is " << cyl.getX() << "\nY coordinate is " << cyl.getY() << "\nRadius is " << cyl.getRadius() << "\nHeight is " << cyl.getHeight() << "\n\n";

// use set functions to change the Cylinder's attributes cyl.setHeight( 10 ); cyl.setRadius( 4.25 ); cyl.setPoint( 2, 2 ); cout << "The new location, radius, and height of cyl are:\n" << cyl << '\n';

// display the Cylinder as a Point Point &pRef1 = cyl; // pRef1 "thinks" that cyl is a Point cout << "\nCylinder printed as a Point is: " << pRef1 << "\n\n";

// display the Cylinder as a Circle Circle &circleRef = cyl; // circleRef thinks that cyl is a Circle cout << "Cylinder printed as a Circle is:\n" << circleRef << "\nArea: " << circleRef.area() << endl;

return 0; }

Test run:

X coordinate is 10 Y coordinate is 37 Radius is 43

The new location and radius of c are Center = [2, 2]; Radius = 4.25 Area 56.74

Circle printed as a Point is: [2, 2]

Circle printed as a Point is: [2, 2]

5 Circle printed via a pointer: Center = [2, 2]; Radius = 4.25

The new location, radius, and height of cyl are: Center = [2, 2]; Radius = 4.25; Height = 10.00

Cylinder printed as a Point is: [2, 2]

Cylinder printed as a Circle is: Center = [2, 2]; Radius = 4.25 Area: 56.74 106 Testing the Point-Circle-Cylinder Hierarchy

Point p1 = c; //Slicing: Copy construct p1 using the Point part of c cout << "\nCircle printed as a Point is: " << p1 << endl; Point *pPtr = &c; // Can only refer to the "Point part" of c cout << "\nCircle printed as a Point is: " << *pPtr << endl; Circle* cPtr = &c; cout << "\nCircle printed via a pointer: " << *cPtr << endl; // create a Cylinder object Cylinder cyl( 5.7, 2.5, 12, 23 ); // use get functions to display the Cylinder cout << "X coordinate is " << cyl.getX() << "\nY coordinate is " << cyl.getY() << "\nRadius is " << cyl.getRadius() << "\nHeight is " << cyl.getHeight() << "\n\n";

// use set functions to change the Cylinder's attributes cyl.setHeight( 10 ); cyl.setRadius( 4.25 ); cyl.setPoint( 2, 2 ); cout << "The new location, radius, and height of cyl are:\n" << cyl << '\n';

// display the Cylinder as a Point Point &pRef1 = cyl; // pRef1 "thinks" that cyl is a Point cout << "\nCylinder printed as a Point is: " << pRef1 << "\n\n";

// display the Cylinder as a Circle Circle &circleRef = cyl; // circleRef thinks that cyl is a Circle cout << "Cylinder printed as a Circle is:\n" << circleRef << "\nArea: " << circleRef.area() << endl;

return 0; }

Test run:

X coordinate is 10 Y coordinate is 37 Radius is 43

The new location and radius of c are Center = [2, 2]; Radius = 4.25 Area 56.74

Circle printed as a Point is: [2, 2]

Circle printed as a Point is: [2, 2]

Circle printed via a pointer: Center = [2, 2]; Radius = 4.25

The new location, radius, and height of cyl are: Center = [2, 2]; Radius = 4.25; Height = 10.00

6 Cylinder printed as a Point is: [2, 2]

Cylinder printed as a Circle is: Center = [2, 2]; Radius = 4.25 Area: 56.74 107 Testing the Point-Circle-Cylinder Hierarchy

Point p1 = c; //Slicing: Copy construct p1 using the Point part of c cout << "\nCircle printed as a Point is: " << p1 << endl; Point *pPtr = &c; // Can only refer to the "Point part" of c cout << "\nCircle printed as a Point is: " << *pPtr << endl; Circle* cPtr = &c; cout << "\nCircle printed via a pointer: " << *cPtr << endl; // create a Cylinder object Cylinder cyl( 5.7, 2.5, 12, 23 ); // use get functions to display the Cylinder cout << "X coordinate is " << cyl.getX() << "\nY coordinate is " << cyl.getY() << "\nRadius is " << cyl.getRadius() << "\nHeight is " << cyl.getHeight() << "\n\n";

// use set functions to change the Cylinder's attributes cyl.setHeight( 10 ); cyl.setRadius( 4.25 ); cyl.setPoint( 2, 2 ); cout << "The new location, radius, and height of cyl are:\n" << cyl << '\n';

// display the Cylinder as a Point Point &pRef1 = cyl; // pRef1 "thinks" that cyl is a Point cout << "\nCylinder printed as a Point is: " << pRef1 << "\n\n";

// display the Cylinder as a Circle Circle &circleRef = cyl; // circleRef thinks that cyl is a Circle cout << "Cylinder printed as a Circle is:\n" << circleRef << "\nArea: " << circleRef.area() << endl;

return 0; }

Test run:

X coordinate is 10 Y coordinate is 37 Radius is 43

The new location and radius of c are Center = [2, 2]; Radius = 4.25 Area 56.74

Circle printed as a Point is: [2, 2]

Circle printed as a Point is: [2, 2]

Circle printed via a pointer: Center = [2, 2]; Radius = 4.25

The new location, radius, and height of cyl are: Center = [2, 2]; Radius = 4.25; Height = 10.00

Cylinder printed as a Point is: [2, 2]

Cylinder printed as a Circle is: Center = [2, 2]; Radius = 4.25 Area: 56.74

7 108 Testing the Point-Circle-Cylinder Hierarchy cout << "\nCircle printed via a pointer: " << *cPtr << endl; // create a Cylinder object Cylinder cyl( 5.7, 2.5, 12, 23 ); // use get functions to display the Cylinder cout << "X coordinate is " << cyl.getX() << "\nY coordinate is " << cyl.getY() << "\nRadius is " << cyl.getRadius() << "\nHeight is " << cyl.getHeight() << "\n\n";

// use set functions to change the Cylinder's attributes cyl.setHeight( 10 ); cyl.setRadius( 4.25 ); cyl.setPoint( 2, 2 ); cout << "The new location, radius, and height of cyl are:\n" << cyl << '\n';

// display the Cylinder as a Point Point &pRef1 = cyl; // pRef1 "thinks" that cyl is a Point cout << "\nCylinder printed as a Point is: " << pRef1 << "\n\n";

// display the Cylinder as a Circle Circle &circleRef = cyl; // circleRef thinks that cyl is a Circle cout << "Cylinder printed as a Circle is:\n" << circleRef << "\nArea: " << circleRef.area() << endl;

return 0; }

Test run:

X coordinate is 10 Y coordinate is 37 Radius is 43

The new location and radius of c are Center = [2, 2]; Radius = 4.25 Area 56.74

Circle printed as a Point is: [2, 2]

Circle printed as a Point is: [2, 2]

Circle printed via a pointer: Center = [2, 2]; Radius = 4.25

The new location, radius, and height of cyl are: Center = [2, 2]; Radius = 4.25; Height = 10.00

Cylinder printed as a Point is: [2, 2]

Cylinder printed as a Circle is: Center = [2, 2]; Radius = 4.25 Area: 56.74 109 Testing the Point-Circle-Cylinder Hierarchy cout << "The new location, radius, and height of cyl are:\n” << cyl << '\n';

// display the Cylinder as a Point Point &pRef1 = cyl; // pRef1 "thinks" that cyl is a Point cout << "\nCylinder printed as a Point is: " << pRef1 << "\n\n";

// display the Cylinder as a Circle Circle &circleRef = cyl; // circleRef thinks that cyl is a Circle cout << "Cylinder printed as a Circle is:\n" << circleRef

8 << "\nArea: " << circleRef.area() << endl; return 0; }

Test run:

X coordinate is 10 Y coordinate is 37 Radius is 43

The new location and radius of c are Center = [2, 2]; Radius = 4.25 Area 56.74

Circle printed as a Point is: [2, 2]

Circle printed as a Point is: [2, 2]

Circle printed via a pointer: Center = [2, 2]; Radius = 4.25

The new location, radius, and height of cyl are: Center = [2, 2]; Radius = 4.25; Height = 10.00

Cylinder printed as a Point is: [2, 2]

Cylinder printed as a Circle is: Center = [2, 2]; Radius = 4.25 Area: 56.74 110 Testing the Point-Circle-Cylinder Hierarchy Test run: X coordinate is 10 Y coordinate is 37 Radius is 43 The new location and radius of c are Center = [2, 2]; Radius = 4.25 Area 56.74 Circle printed as a Point is: [2, 2] Circle printed as a Point is: [2, 2] Circle printed via a pointer: Center = [2, 2]; Radius = 4.25 The new location, radius, and height of cyl are: Center = [2, 2]; Radius = 4.25; Height = 10.00 Cylinder printed as a Point is: [2, 2] Cylinder printed as a Circle is: Center = [2, 2]; Radius = 4.25 Area: 56.74

9