022 Other Topics

55
2003 Prentice Hall, Inc. All rights reserved. 1 Chapter 22 - Other Topics Outline 22.1 Introduction 22.2 const_cast Operator 22.3 reinterpret_cast Operator 22.4 namespaces 22.5 Operator Keywords 22.6 explicit Constructors 22.7 mutable Class Members 22.8 Pointers to Class Members (.* and ->*) 22.9 Multiple Inheritance 22.10 Multiple Inheritance and virtual Base Classes

description

programming

Transcript of 022 Other Topics

Page 1: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

1

Chapter 22 - Other Topics

Outline22.1 Introduction22.2 const_cast Operator22.3 reinterpret_cast Operator22.4 namespaces22.5 Operator Keywords22.6 explicit Constructors22.7 mutable Class Members22.8 Pointers to Class Members (.* and ->*)22.9 Multiple Inheritance22.10 Multiple Inheritance and virtual Base Classes

Page 2: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

2

22.1 Introduction

• Consider additional C++ features– Cast operators– Namespaces– Operator keywords– Multiple inheritence

Page 3: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

3

22.2 const_cast Operator

• const_cast operator– Used to cast away const or volatile

• Get rid of a variable's "const-ness"– const_cast < new data type >

Page 4: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline4

fig22_01.cpp(1 of 2)

1 // Fig. 22.1: fig22_01.cpp2 // Demonstrating operator const_cast. 3 #include <iostream>4 5 using std::cout;6 using std::endl;7 8 // class ConstCastTest definition9 class ConstCastTest {10 public:11 void setNumber( int );12 int getNumber() const;13 void printNumber() const;14 private:15 int number;16 }; // end class ConstCastTest17 18 // set number19 void ConstCastTest::setNumber( int num ) { number = num; }20 21 // return number22 int ConstCastTest::getNumber() const { return number; }23

Function is const, and cannot modify data.

Page 5: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline5

fig22_01.cpp(2 of 2)

fig22_01.cppoutput (1 of 1)

24 // output number25 void ConstCastTest::printNumber() const26 {27 cout << "\nNumber after modification: ";28 29 // cast away const-ness to allow modification 30 const_cast< ConstCastTest * >( this )->number--;31 32 cout << number << endl;33 34 } // end printNumber35 36 int main()37 {38 ConstCastTest test; // create ConstCastTest instance39 40 test.setNumber( 8 ); // set private data number to 841 42 cout << "Initial value of number: " << test.getNumber();43 44 test.printNumber();45 return 0;46 47 } // end main

Initial value of number: 8Number after modification: 7

Cast away the const-ness the this pointer. This allows the data to be modified.

Page 6: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

6

22.3 reinterpret_cast Operator

• reinterpret_cast– Used for nonstandard casts (i.e., one pointer to another)

• int * to char *– Cannot be used for standard casts (i.e, double to int)

Page 7: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline7

fig22_02.cpp(1 of 1)

fig22_02.cppoutput (1 of 1)

1 // Fig. 22.2: fig22_02.cpp2 // Demonstrating operator reinterpret_cast.3 #include <iostream>4 5 using std::cout;6 using std::endl;7 8 int main()9 {10 int x = 120;11 int *ptr = &x;12 13 // use reinterpret_cast to cast from int * to char *14 cout << *reinterpret_cast< char * >( ptr ) << endl; 15 16 return 0;17 18 } // end main

x

Create an int *. Cast it to a char * for printing. 120 is the ASCII value of 'x'.

Page 8: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

8

22.4 namespaces

• Program has identifiers in different scopes– Sometimes scopes overlap, lead to problems

• Namespace defines scope– Place identifiers and variables within namespace– Access with namespace_name::member– Note guaranteed to be unique

namespace Name { contents}

– Unnamed namespaces are global• Need no qualification

– Namespaces can be nested

Page 9: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

9

22.4 namespaces

• using statement– using namespace namespace_name;– Members of that namespace can be used without preceding namespace_name::

• Can also be used with individual member– Examples

• using namespace std– Discouraged by some programmers, because includes

entire contents of std• using namespace std::cout

– Can write cout instead of std::cout

Page 10: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline10

fig22_03.cpp(1 of 3)

1 // Fig. 22.3: fig22_03.cpp2 // Demonstrating namespaces.3 #include <iostream>4 5 using namespace std; // use std namespace 6 7 int integer1 = 98; // global variable8 9 // create namespace Example 10 namespace Example { 11 12 // declare two constants and one variable 13 const double PI = 3.14159; 14 const double E = 2.71828; 15 int integer1 = 8; 16 17 void printValues(); // prototype 18 19 // nested namespace 20 namespace Inner { 21 22 // define enumeration 23 enum Years { FISCAL1 = 1990, FISCAL2, FISCAL3 };24 25 } // end Inner 26 27 } // end Example

Note the using statement. This includes all of std, allowing us to use cout and endl.

Note the nested namespace Inner.

Create a new namespace, Example. Note that it has a variable integer1, different from the global integer1.

Page 11: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline11

fig22_03.cpp(2 of 3)

28 29 // create unnamed namespace 30 namespace { 31 double doubleInUnnamed = 88.22; // declare variable32 33 } // end unnamed namespace 34 35 int main()36 {37 // output value doubleInUnnamed of unnamed namespace38 cout << "doubleInUnnamed = " << doubleInUnnamed;39 40 // output global variable41 cout << "\n(global) integer1 = " << integer1;42 43 // output values of Example namespace44 cout << "\nPI = " << Example::PI << "\nE = "45 << Example::E << "\ninteger1 = " 46 << Example::integer1 << "\nFISCAL3 = "47 << Example::Inner::FISCAL3 << endl;48 49 Example::printValues(); // invoke printValues function50 51 return 0;52 53 } // end main

Create an unnamed namespace. Its variables are global.

Page 12: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline12

fig22_03.cpp(3 of 3)

54 55 // display variable and constant values56 void Example::printValues() 57 {58 cout << "\nIn printValues:\ninteger1 = "59 << integer1 << "\nPI = " << PI << "\nE = "60 << E << "\ndoubleInUnnamed = " << doubleInUnnamed 61 << "\n(global) integer1 = " << ::integer162 << "\nFISCAL3 = " << Inner::FISCAL3 << endl;63 64 } // end printValues

Page 13: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline13

fig22_03.cppoutput (1 of 1)

doubleInUnnamed = 88.22(global) integer1 = 98PI = 3.14159E = 2.71828integer1 = 8FISCAL3 = 1992 In printValues:integer1 = 8PI = 3.14159E = 2.71828doubleInUnnamed = 88.22(global) integer1 = 98FISCAL3 = 1992

Page 14: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

14

22.5 Operator Keywords

• Operator keywords– Can be used instead of operators– Useful for keyboards without ^ | & etc.

Page 15: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

15

22.5 Operator Keywords

Operator Operator keyword Description Logical operator keywords

&& and logical AND || or logical OR ! not logical NOT Inequality operator keyword

!= not_eq Inequality Bitwise operator keywords

& bitand Bitwise AND | bitor Bitwise inclusive OR ^ xor Bitwise exclusive OR ~ compl Bitwise complement Bitwise assignment operator keywords

&= and_eq Bitwise AND assignment |= or_eq Bitwise inclusive OR

assignment ^= xor_eq Bitwise exclusive OR

assignment

Page 16: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline16

fig22_05.cpp(1 of 2)

1 // Fig. 22.5: fig22_05.cpp2 // Demonstrating operator keywords.3 #include <iostream>4 5 using std::cout;6 using std::endl;7 using std::boolalpha;8 9 #include <iso646.h>10 11 int main()12 {13 int a = 2;14 int b = 3;15 16 cout << boolalpha 17 << " a and b: " << ( a and b ) 18 << "\n a or b: " << ( a or b ) 19 << "\n not a: " << ( not a ) 20 << "\na not_eq b: " << ( a not_eq b )21 << "\na bitand b: " << ( a bitand b )22 << "\na bit_or b: " << ( a bitor b ) 23 << "\n a xor b: " << ( a xor b ) 24 << "\n compl a: " << ( compl a ) 25 << "\na and_eq b: " << ( a and_eq b )26 << "\n a or_eq b: " << ( a or_eq b ) 27 << "\na xor_eq b: " << ( a xor_eq b ) << endl;

Note use of operator keywords.

Page 17: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline17

fig22_05.cpp(2 of 2)

fig22_05.cppoutput (1 of 1)

28 29 return 0;30 31 } // end main

a and b: true a or b: true not a: falsea not_eq b: falsea bitand b: 3a bit_or b: 3 a xor b: 0 compl a: -4a and_eq b: 3 a or_eq b: 3a xor_eq b: 1

Page 18: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

18

22.6 explicit Constructors

• Implicit conversions– In Chapter 8, compiler may perform implicitly

• If constructor exists– Suppose we have constructor

• myClass( int x )– Define function

• myFunction( myClass y )– Now, call myFunction( 3 )

• Compiler implicitly converts 3 to myClass, using the constructor

• Then calls myFunction with the new object

Page 19: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

19

22.6 explicit Constructors

• May not have desired behavior– Declare constructor explicit

• Cannot be used in implicit conversions

• Example– First show Array class with implicit conversion– Then show Array class with explicit constructor

Page 20: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline20

array.h (1 of 1)

1 // Fig 22.6: array.h2 // Simple class Array (for integers).3 #ifndef ARRAY_H4 #define ARRAY_H5 6 #include <iostream>7 8 using std::ostream;9 10 // class Array definition11 class Array {12 friend ostream &operator<<( ostream &, const Array & );13 public:14 Array( int = 10 ); // default/conversion constructor15 ~Array(); // destructor16 private:17 int size; // size of the array18 int *ptr; // pointer to first element of array19 20 }; // end class Array21 22 #endif // ARRAY_H

Without the explicit keyword, this constructor can be used for implicit conversions.

Page 21: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline21

array.cpp (1 of 2)

1 // Fig 22.7: array.cpp2 // Member function definitions for class Array.3 #include <iostream>4 5 using std::cout;6 using std::ostream;7 8 #include <new>9 10 #include "array.h"11 12 // default constructor for class Array (default size 10)13 Array::Array( int arraySize )14 {15 size = ( arraySize < 0 ? 10 : arraySize ); 16 cout << "Array constructor called for " 17 << size << " elements\n";18 19 // create space for array20 ptr = new int[ size ]; 21 22 // initialize array elements to zeroes23 for ( int i = 0; i < size; i++ )24 ptr[ i ] = 0; 25 26 } // end constructor

Page 22: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline22

array.cpp (2 of 2)

27 28 // destructor for class Array29 Array::~Array() { delete [] ptr; }30 31 // overloaded stream insertion operator for class Array 32 ostream &operator<<( ostream &output, const Array &arrayRef )33 {34 for ( int i = 0; i < arrayRef.size; i++ )35 output << arrayRef.ptr[ i ] << ' ' ;36 37 return output; // enables cout << x << y;38 39 } // end operator<<

Page 23: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline23

fig22_08.cpp(1 of 2)

1 // Fig 22.8: fig22_08.cpp2 // Driver for simple class Array.3 #include <iostream>4 5 using std::cout;6 7 #include "array.h"8 9 void outputArray( const Array & );10 11 int main()12 {13 Array integers1( 7 );14 15 outputArray( integers1 ); // output Array integers116 17 outputArray( 15 ); // convert 15 to an Array and output 18 19 return 0;20 21 } // end main

Call outputArray and pass an int. This works because the int is implicitly converted to an Array by the constructor.

Page 24: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline24

fig22_08.cpp(2 of 2)

fig22_08.cppoutput (1 of 1)

22 23 // print array contents24 void outputArray( const Array &arrayToOutput )25 {26 cout << "The array received contains:\n" 27 << arrayToOutput << "\n\n";28 29 } // end outputArray

Array constructor called for 7 elementsThe array received contains:0 0 0 0 0 0 0 Array constructor called for 15 elementsThe array received contains:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Page 25: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline25

array.h (1 of 1)

1 // Fig. 22.9: array.h2 // Simple class Array (for integers).3 #ifndef ARRAY_H4 #define ARRAY_H5 6 #include <iostream>7 8 using std::ostream;9 10 // class Array definition11 class Array {12 friend ostream &operator<<( ostream &, const Array & );13 public:14 explicit Array( int = 10 ); // default constructor15 ~Array(); // destructor16 private:17 int size; // size of the array18 int *ptr; // pointer to first element of array19 20 }; // end class Array21 22 #endif // ARRAY_H

This time, declare constructor explicit.

Page 26: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline26

array.cpp (1 of 2)

1 // Fig. 22.10: array.cpp2 // Member function definitions for class Array.3 #include <iostream>4 5 using std::cout;6 using std::ostream;7 8 #include <new>9 10 #include "array.h"11 12 // default constructor for class Array (default size 10)13 Array::Array( int arraySize )14 {15 size = ( arraySize < 0 ? 10 : arraySize ); 16 cout << "Array constructor called for " 17 << size << " elements\n";18 19 // create space for array20 ptr = new int[ size ];21 22 // initialize array elements to zeroes23 for ( int i = 0; i < size; i++ )24 ptr[ i ] = 0;25 26 } // end constructor

Page 27: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline27

array.cpp (2 of 2)

27 28 // destructor for class Array29 Array::~Array() { delete [] ptr; }30 31 // overloaded insertion operator for class Array 32 ostream &operator<<( ostream &output, const Array &arrayRef )33 {34 for ( int i = 0; i < arrayRef.size; i++ )35 output << arrayRef.ptr[ i ] << ' ' ;36 37 return output; // enables cout << x << y;38 39 } // end operator<<

Page 28: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline28

fig22_11.cpp(1 of 2)

1 // Fig. 22.11: fig22_11.cpp2 // Driver for simple class Array.3 #include <iostream>4 5 using std::cout;6 7 #include "array.h"8 9 void outputArray( const Array & );10 11 int main()12 {13 Array integers1( 7 );14 15 outputArray( integers1 ); // output Array integers116 17 // ERROR: construction not allowed 18 outputArray( 15 ); // convert 15 to an Array and output 19 20 outputArray( Array( 15 ) ); // must use constructor 21 22 return 0;23 24 } // end main25

This call will cause an error when compiled.

Page 29: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline29

fig22_11.cpp(2 of 2)

fig22_11.cppoutput (1 of 1)

26 // display array contents27 void outputArray( const Array &arrayToOutput )28 {29 cout << "The array received contains:\n" 30 << arrayToOutput << "\n\n";31 32 } // end outputArray

c:\cpp4e\ch22\FIG22_09_10_11\Fig22_11.cpp(18) : error C2664: 'outputArray' : cannot convert parameter 1 from 'const int' to 'const class Array &'Reason: cannot convert from 'const int' to 'const class Array'No constructor could take the source type, or constructor overload resolution was ambiguousError executing cl.exe. test.exe - 1 error(s), 0 warning(s)

Page 30: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

30

22.7 mutable Class Members

• mutable data member– Always modifiable, even in a const function or object– Avoid need for const_cast

• const_cast vs. mutable– For const object with no mutable data members

• const_cast used every time• Reduces chance of accidental change

Page 31: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline31

fig21_12.cpp(1 of 2)

1 // Fig. 21.12: fig21_12.cpp2 // Demonstrating storage class specifier mutable.3 #include <iostream>4 5 using std::cout;6 using std::endl;7 8 // class TestMutable definition9 class TestMutable {10 public:11 TestMutable( int v = 0 ) { value = v; }12 void modifyValue() const { value++; } 13 int getValue() const { return value; }14 private:15 mutable int value; // mutable member 16 17 }; // end class TestMutable18 19 int main()20 {21 const TestMutable test( 99 );22 23 cout << "Initial value: " << test.getValue();24 25 test.modifyValue(); // modifies mutable member26 cout << "\nModified value: " << test.getValue() << endl;

Declare a mutable int. It can be modified by const functions.

Page 32: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline32

fig21_12.cpp(2 of 2)

fig21_12.cppoutput (1 of 1)

27 28 return 0;29 30 } // end main

Initial value: 99Modified value: 100

Page 33: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

33

22.8 Pointers to Class Members (.* and ->*)

• Use to access class members– Not the same as previously discussed pointers

• Class function– void *memPtr ()

• Regular function pointer, to function that returns void and takes no arguments

– void ( Test::*memPtr )()• Pointer to function in class Test• Function returns void, takes no arguments

– To call function• Need pointer to Test object (tPtr)• (tPtr->*memPtr)()

Page 34: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

34

22.8 Pointers to Class Members (.* and ->*)

• Class data member– int *vPtr

• Regular pointer to an int– int Test::*vPtr

• Pointer to an int member of class Test– To access

• Need pointer to object (tPtr)• (*tPtr).*vPtr

Page 35: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline35

fig22_13.cpp(1 of 2)

1 // Fig. 22.13 : fig22_13.cpp2 // Demonstrating operators .* and ->*.3 #include <iostream>4 5 using std::cout;6 using std::endl;7 8 // class Test definition9 class Test {10 public:11 void function() { cout << "function\n"; }12 int value; // public data member13 }; // end class Test14 15 void arrowStar( Test * );16 void dotStar( Test * );17 18 int main()19 {20 Test test; 21 22 test.value = 8; // assign value 8 23 arrowStar( &test ); // pass address to arrowStar24 dotStar( &test ); // pass address to dotStar

Page 36: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline36

fig22_13.cpp(2 of 2)

25 26 return 0;27 28 } // end main29 30 // access member function of Test object using ->*31 void arrowStar( Test *testPtr )32 {33 // declare function pointer 34 void ( Test::*memPtr )() = &Test::function;35 36 // invoke function indirectly37 ( testPtr->*memPtr )(); 38 39 } // end arrowStar40 41 // access members of Test object data member using .*42 void dotStar( Test *testPtr2 )43 {44 int Test::*vPtr = &Test::value; // declare pointer 45 46 cout << ( *testPtr2 ).*vPtr << endl; // access value47 48 } // end dotStar

Assign function pointer to the address of function in Test. Note that neither side refers to a specific object.

Next, call function directly.

Create pointer to data member value. Then, access the data.

Page 37: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline37

fig22_13.cppoutput (1 of 1)

function8

Page 38: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

38

22.9 Multiple Inheritance

• Multiple inheritence– Derived class has several base classes– Powerful, but can cause ambiguity problems

• If both base classes have functions of the same name• Solution: specify exact function using ::

– myObject.BaseClass1::function()– Format

• Use comma-separated list class Derived : public Base1, public Base2{ contents}

Page 39: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline39

base1.h (1 of 1)

1 // Fig. 22.14: base1.h2 // Definition of class Base13 #ifndef BASE1_H4 #define BASE1_H5 6 // class Base1 definition7 class Base1 {8 public:9 Base1( int parameterValue ) { value = parameterValue; }10 int getData() const { return value; }11 12 protected: // accessible to derived classes13 int value; // inherited by derived class14 15 }; // end class Base116 17 #endif // BASE1_H

There are two base classes in this example, each has its own getData function.

This base class contains an int.

Page 40: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline40

base2.h (1 of 1)

1 // Fig. 22.15: base2.h2 // Definition of class Base23 #ifndef BASE2_H4 #define BASE2_H5 6 // class Base2 definition7 class Base2 {8 public:9 Base2( char characterData ) { letter = characterData; }10 char getData() const { return letter; }11 12 protected: // accessible to derived classes13 char letter; // inherited by derived class14 15 }; // end class Base216 17 #endif // BASE2_H

Page 41: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline41

derived.h (1 of 1)

1 // Fig. 22.16: derived.h2 // Definition of class Derived which inherits3 // multiple base classes (Base1 and Base2).4 #ifndef DERIVED_H5 #define DERIVED_H6 7 #include <iostream>8 9 using std::ostream;10 11 #include "base1.h"12 #include "base2.h"13 14 // class Derived definition15 class Derived : public Base1, public Base2 {16 friend ostream &operator<<( ostream &, const Derived & );17 18 public:19 Derived( int, char, double );20 double getReal() const;21 22 private:23 double real; // derived class's private data24 25 }; // end class Derived26 27 #endif // DERIVED_H

Use comma-separated list.

Page 42: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline42

derived.cpp (1 of 1)

1 // Fig. 22.17: derived.cpp2 // Member function definitions for class Derived3 #include "derived.h"4 5 // constructor for Derived calls constructors for 6 // class Base1 and class Base2. 7 // use member initializers to call base-class constructors 8 Derived::Derived( int integer, char character, double double1 )9 : Base1( integer ), Base2( character ), real( double1 ) { } 10 11 // return real12 double Derived::getReal() const { return real; }13 14 // display all data members of Derived15 ostream &operator<<( ostream &output, const Derived &derived )16 {17 output << " Integer: " << derived.value 18 << "\n Character: " << derived.letter19 << "\nReal number: " << derived.real;20 21 return output; // enables cascaded calls22 23 } // end operator<<

Note use of base-class constructors in derived class constructor.

Page 43: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline43

fig22_18.cpp(1 of 2)

1 // Fig. 22.18: fig22_18.cpp2 // Driver for multiple inheritance example.3 #include <iostream>4 5 using std::cout;6 using std::endl;7 8 #include "base1.h"9 #include "base2.h"10 #include "derived.h"11 12 int main()13 {14 Base1 base1( 10 ), *base1Ptr = 0; // create Base1 object15 Base2 base2( 'Z' ), *base2Ptr = 0; // create Base2 object16 Derived derived( 7, 'A', 3.5 ); // create Derived object17 18 // print data members of base-class objects19 cout << "Object base1 contains integer " 20 << base1.getData() 21 << "\nObject base2 contains character " 22 << base2.getData()23 << "\nObject derived contains:\n" << derived << "\n\n";24

Page 44: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline44

fig22_18.cpp(2 of 2)

25 // print data members of derived-class object26 // scope resolution operator resolves getData ambiguity27 cout << "Data members of Derived can be"28 << " accessed individually:"29 << "\n Integer: " << derived.Base1::getData()30 << "\n Character: " << derived.Base2::getData()31 << "\nReal number: " << derived.getReal() << "\n\n";32 33 cout << "Derived can be treated as an "34 << "object of either base class:\n";35 36 // treat Derived as a Base1 object37 base1Ptr = &derived; 38 cout << "base1Ptr->getData() yields "39 << base1Ptr->getData() << '\n';40 41 // treat Derived as a Base2 object42 base2Ptr = &derived; 43 cout << "base2Ptr->getData() yields "44 << base2Ptr->getData() << endl;45 46 return 0;47 48 } // end main

Note calls to specific base class functions.

Can treat derived-class pointer as either base-class pointer.

Page 45: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline45

fig22_18.cppoutput (1 of 1)

Object base1 contains integer 10Object base2 contains character ZObject derived contains: Integer: 7 Character: AReal number: 3.5 Data members of Derived can be accessed individually: Integer: 7 Character: AReal number: 3.5 Derived can be treated as an object of either base class:base1Ptr->getData() yields 7base2Ptr->getData() yields A

Page 46: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

46

22.10 Multiple Inheritance and virtual Base Classes

• Ambiguities from multiple inheritance

• iostream could have duplicate subobjects– Data from ios inherited into ostream and istream– Upcasting iostream pointer to ios object is a problem

• Two ios subobjects could exist, which is used?– Ambiguous, results in syntax error

• iostream does not actually have this problem

ios

ostreamistream

iostream

Page 47: 022 Other Topics

2003 Prentice Hall, Inc. All rights reserved.

47

22.10 Multiple Inheritance and virtual Base Classes

• Solution: use virtual base class inheritance– Only one subobject inherited into multiply derived class

Second Derived Class

Base Class

First Derived Class

Multiply-Derived Class

virtual inheritance

virtual inheritance

Page 48: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline48

fig22_20.cpp(1 of 3)

1 // Fig. 22.20: fig22_20.cpp2 // Attempting to polymorphically call a function that is3 // multiply inherited from two base classes.4 #include <iostream>5 6 using std::cout;7 using std::endl;8 9 // class Base definition10 class Base {11 public: 12 virtual void print() const = 0; // pure virtual13 14 }; // end class Base15 16 // class DerivedOne definition17 class DerivedOne : public Base {18 public:19 20 // override print function 21 void print() const { cout << "DerivedOne\n"; } 22 23 }; // end class DerivedOne24

This example will demonstrate the ambiguity of multiple inheritance.

Page 49: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline49

fig22_20.cpp(2 of 3)

25 // class DerivedTwo definition26 class DerivedTwo : public Base {27 public:28 29 // override print function 30 void print() const { cout << "DerivedTwo\n"; }31 32 }; // end class DerivedTwo33 34 // class Multiple definition35 class Multiple : public DerivedOne, public DerivedTwo {36 public:37 38 // qualify which version of function print39 void print() const { DerivedTwo::print(); }40 41 }; // end class Multiple42

Page 50: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline50

fig22_20.cpp(3 of 3)

43 int main()44 {45 Multiple both; // instantiate Multiple object46 DerivedOne one; // instantiate DerivedOne object47 DerivedTwo two; // instantiate DerivedTwo object48 49 // create array of base-class pointers50 Base *array[ 3 ];51 52 array[ 0 ] = &both; // ERROR--ambiguous 53 array[ 1 ] = &one;54 array[ 2 ] = &two;55 56 // polymorphically invoke print57 for ( int i = 0; i < 3; i++ )58 array[ i ] -> print();59 60 return 0;61 62 } // end main

Which base subobject will be used?

Page 51: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline51

fig22_20.cppoutput (1 of 1)

c:\cpp4e\ch22\fig22_20_21\fig22_20.cpp(52) : error C2594: '=' : ambiguous conversions from 'class Multiple *' to 'class Base *'Error executing cl.exe. test.exe - 1 error(s), 0 warning(s)

Page 52: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline52

fig22_21.cpp(1 of 3)

1 // Fig. 22.21: fig22_21.cpp2 // Using virtual base classes.3 #include <iostream>4 5 using std::cout;6 using std::endl;7 8 // class Base definition9 class Base {10 public:11 12 // implicit default constructor13 14 virtual void print() const = 0; // pure virtual15 16 }; // end Base class17 18 // class DerivedOne definition19 class DerivedOne : virtual public Base {20 public:21 22 // implicit default constructor calls23 // Base default constructor 24 25 // override print function 26 void print() const { cout << "DerivedOne\n"; }27 28 }; // end DerivedOne class

Use virtual inheritance to solve the ambiguity problem.

The compiler generates default constructors, which greatly simplifies the hierarchy.

Page 53: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline53

fig22_21.cpp(2 of 3)

29 30 // class DerivedTwo definition31 class DerivedTwo : virtual public Base {32 public:33 34 // implicit default constructor calls35 // Base default constructor 36 37 // override print function 38 void print() const { cout << "DerivedTwo\n"; }39 40 }; // end DerivedTwo class41 42 // class Multiple definition43 class Multiple : public DerivedOne, public DerivedTwo {44 public:45 46 // implicit default constructor calls47 // DerivedOne and DerivedTwo default constructors48 49 // qualify which version of function print 50 void print() const { DerivedTwo::print(); } 51 52 }; // end Multiple class

Use virtual inheritance, as before.

Page 54: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline54

fig22_21.cpp(3 of 3)

53 54 int main()55 {56 Multiple both; // instantiate Multiple object57 DerivedOne one; // instantiate DerivedOne object58 DerivedTwo two; // instantiate DerivedTwo object59 60 // declare array of base-class pointers and initialize61 // each element to a derived-class type62 Base *array[ 3 ];63 64 array[ 0 ] = &both; 65 array[ 1 ] = &one;66 array[ 2 ] = &two;67 68 // polymorphically invoke function print69 for ( int i = 0; i < 3; i++ )70 array[ i ]->print();71 72 return 0;73 74 } // end main

Page 55: 022 Other Topics

2003 Prentice Hall, Inc.All rights reserved.

Outline55

fig22_21.cppoutput (1 of 1)

DerivedTwoDerivedOneDerivedTwo