Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 22 - Other Topics Outline 22.1 Introduction

Similar presentations


Presentation on theme: "Chapter 22 - Other Topics Outline 22.1 Introduction"— Presentation transcript:

1 Chapter 22 - Other Topics Outline 22.1 Introduction
const_cast Operator reinterpret_cast Operator namespaces Operator Keywords explicit Constructors mutable Class Members Pointers to Class Members (.* and ->*) Multiple Inheritance Multiple Inheritance and virtual Base Classes

2 Consider additional C++ features
Introduction Consider additional C++ features Cast operators Namespaces Operator keywords Multiple inheritence

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 >

4 Function is const, and cannot modify data.
// Fig. 22.1: fig22_01.cpp // Demonstrating operator const_cast. #include <iostream> 4 using std::cout; using std::endl; 7 // class ConstCastTest definition class ConstCastTest { 10 public: void setNumber( int ); int getNumber() const; void printNumber() const; 14 private: int number; 16 }; // end class ConstCastTest 17 18 // set number 19 void ConstCastTest::setNumber( int num ) { number = num; } 20 21 // return number 22 int ConstCastTest::getNumber() const { return number; } 23 fig22_01.cpp (1 of 2) Function is const, and cannot modify data.

5 fig22_01.cpp (2 of 2) fig22_01.cpp output (1 of 1)
24 // output number 25 void ConstCastTest::printNumber() const 26 { cout << "\nNumber after modification: "; 28 // cast away const-ness to allow modification const_cast< ConstCastTest * >( this )->number--; 31 cout << number << endl; 33 34 } // end printNumber 35 36 int main() 37 { ConstCastTest test; // create ConstCastTest instance 39 test.setNumber( 8 ); // set private data number to 8 41 cout << "Initial value of number: " << test.getNumber(); 43 test.printNumber(); return 0; 46 47 } // end main Cast away the const-ness the this pointer. This allows the data to be modified. fig22_01.cpp (2 of 2) fig22_01.cpp output (1 of 1) Initial value of number: 8 Number after modification: 7

6 22.3 reinterpret_cast Operator
Used for nonstandard casts (i.e., one pointer to another) int * to char * Cannot be used for standard casts (i.e, double to int)

7 fig22_02.cpp (1 of 1) fig22_02.cpp output (1 of 1)
// Fig. 22.2: fig22_02.cpp // Demonstrating operator reinterpret_cast. #include <iostream> 4 using std::cout; using std::endl; 7 int main() { int x = 120; int *ptr = &x; 12 // use reinterpret_cast to cast from int * to char * cout << *reinterpret_cast< char * >( ptr ) << endl; 15 return 0; 17 18 } // end main fig22_02.cpp (1 of 1) fig22_02.cpp output (1 of 1) Create an int *. Cast it to a char * for printing. 120 is the ASCII value of 'x'. x

8 Program has identifiers in different scopes Namespace defines scope
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

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

10 Note the nested namespace Inner.
// Fig. 22.3: fig22_03.cpp // Demonstrating namespaces. #include <iostream> 4 using namespace std; // use std namespace 6 int integer1 = 98; // global variable 8 // create namespace Example 10 namespace Example { 11 // declare two constants and one variable const double PI = ; const double E = ; int integer1 = 8; 16 void printValues(); // prototype 18 // nested namespace namespace Inner { 21 // define enumeration enum Years { FISCAL1 = 1990, FISCAL2, FISCAL3 }; 24 } // end Inner 26 27 } // end Example Note the using statement. This includes all of std, allowing us to use cout and endl. fig22_03.cpp (1 of 3) Create a new namespace, Example. Note that it has a variable integer1, different from the global integer1. Note the nested namespace Inner.

11 Create an unnamed namespace. Its variables are global.
28 29 // create unnamed namespace 30 namespace { double doubleInUnnamed = 88.22; // declare variable 32 33 } // end unnamed namespace 34 35 int main() 36 { // output value doubleInUnnamed of unnamed namespace cout << "doubleInUnnamed = " << doubleInUnnamed; 39 // output global variable cout << "\n(global) integer1 = " << integer1; 42 // output values of Example namespace cout << "\nPI = " << Example::PI << "\nE = " << Example::E << "\ninteger1 = " << Example::integer1 << "\nFISCAL3 = " << Example::Inner::FISCAL3 << endl; 48 Example::printValues(); // invoke printValues function 50 return 0; 52 53 } // end main Create an unnamed namespace. Its variables are global. fig22_03.cpp (2 of 3)

12 fig22_03.cpp (3 of 3) 54 55 // display variable and constant values
56 void Example::printValues() 57 { cout << "\nIn printValues:\ninteger1 = " << integer1 << "\nPI = " << PI << "\nE = " << E << "\ndoubleInUnnamed = " << doubleInUnnamed << "\n(global) integer1 = " << ::integer1 << "\nFISCAL3 = " << Inner::FISCAL3 << endl; 63 64 } // end printValues fig22_03.cpp (3 of 3)

13 fig22_03.cpp output (1 of 1) doubleInUnnamed = 88.22
(global) integer1 = 98 PI = E = integer1 = 8 FISCAL3 = 1992 In printValues: fig22_03.cpp output (1 of 1)

14 22.5 Operator Keywords Operator keywords
Can be used instead of operators Useful for keyboards without ^ | & etc.

15 Operator Keywords

16 Note use of operator keywords.
// Fig. 22.5: fig22_05.cpp // Demonstrating operator keywords. #include <iostream> 4 using std::cout; using std::endl; using std::boolalpha; 8 #include <iso646.h> 10 11 int main() 12 { int a = 2; int b = 3; 15 cout << boolalpha << " a and b: " << ( a and b ) << "\n a or b: " << ( a or b ) << "\n not a: " << ( not a ) << "\na not_eq b: " << ( a not_eq b ) << "\na bitand b: " << ( a bitand b ) << "\na bit_or b: " << ( a bitor b ) << "\n a xor b: " << ( a xor b ) << "\n compl a: " << ( compl a ) << "\na and_eq b: " << ( a and_eq b ) << "\n a or_eq b: " << ( a or_eq b ) << "\na xor_eq b: " << ( a xor_eq b ) << endl; fig22_05.cpp (1 of 2) Note use of operator keywords.

17 fig22_05.cpp (2 of 2) fig22_05.cpp output (1 of 1)
28 return 0; 30 31 } // end main fig22_05.cpp (2 of 2) fig22_05.cpp output (1 of 1) a and b: true a or b: true not a: false a not_eq b: false a bitand b: 3 a bit_or b: 3 a xor b: 0 compl a: -4 a and_eq b: 3 a or_eq b: 3 a xor_eq b: 1

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

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

20 // Fig 22.6: array.h // Simple class Array (for integers). #ifndef ARRAY_H #define ARRAY_H 5 #include <iostream> 7 using std::ostream; 9 10 // class Array definition 11 class Array { friend ostream &operator<<( ostream &, const Array & ); 13 public: Array( int = 10 ); // default/conversion constructor ~Array(); // destructor 16 private: int size; // size of the array int *ptr; // pointer to first element of array 19 20 }; // end class Array 21 22 #endif // ARRAY_H array.h (1 of 1) Without the explicit keyword, this constructor can be used for implicit conversions.

21 array.cpp (1 of 2) 1 // Fig 22.7: array.cpp
// Member function definitions for class Array. #include <iostream> 4 using std::cout; using std::ostream; 7 #include <new> 9 10 #include "array.h" 11 12 // default constructor for class Array (default size 10) 13 Array::Array( int arraySize ) 14 { size = ( arraySize < 0 ? 10 : arraySize ); cout << "Array constructor called for " << size << " elements\n"; 18 // create space for array ptr = new int[ size ]; 21 // initialize array elements to zeroes for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; 25 26 } // end constructor array.cpp (1 of 2)

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

23 // Fig 22.8: fig22_08.cpp // Driver for simple class Array. #include <iostream> 4 using std::cout; 6 #include "array.h" 8 void outputArray( const Array & ); 10 11 int main() 12 { Array integers1( 7 ); 14 outputArray( integers1 ); // output Array integers1 16 outputArray( 15 ); // convert 15 to an Array and output 18 return 0; 20 21 } // end main fig22_08.cpp (1 of 2) Call outputArray and pass an int. This works because the int is implicitly converted to an Array by the constructor.

24 fig22_08.cpp (2 of 2) fig22_08.cpp output (1 of 1)
23 // print array contents 24 void outputArray( const Array &arrayToOutput ) 25 { cout << "The array received contains:\n" << arrayToOutput << "\n\n"; 28 29 } // end outputArray fig22_08.cpp (2 of 2) fig22_08.cpp output (1 of 1) Array constructor called for 7 elements The array received contains: Array constructor called for 15 elements

25 This time, declare constructor explicit.
// Fig. 22.9: array.h // Simple class Array (for integers). #ifndef ARRAY_H #define ARRAY_H 5 #include <iostream> 7 using std::ostream; 9 10 // class Array definition 11 class Array { friend ostream &operator<<( ostream &, const Array & ); 13 public: explicit Array( int = 10 ); // default constructor ~Array(); // destructor 16 private: int size; // size of the array int *ptr; // pointer to first element of array 19 20 }; // end class Array 21 22 #endif // ARRAY_H array.h (1 of 1) This time, declare constructor explicit.

26 array.cpp (1 of 2) 1 // Fig. 22.10: array.cpp
// Member function definitions for class Array. #include <iostream> 4 using std::cout; using std::ostream; 7 #include <new> 9 10 #include "array.h" 11 12 // default constructor for class Array (default size 10) 13 Array::Array( int arraySize ) 14 { size = ( arraySize < 0 ? 10 : arraySize ); cout << "Array constructor called for " << size << " elements\n"; 18 // create space for array ptr = new int[ size ]; 21 // initialize array elements to zeroes for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; 25 26 } // end constructor array.cpp (1 of 2)

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

28 This call will cause an error when compiled.
// Fig : fig22_11.cpp // Driver for simple class Array. #include <iostream> 4 using std::cout; 6 #include "array.h" 8 void outputArray( const Array & ); 10 11 int main() 12 { Array integers1( 7 ); 14 outputArray( integers1 ); // output Array integers1 16 // ERROR: construction not allowed outputArray( 15 ); // convert 15 to an Array and output 19 outputArray( Array( 15 ) ); // must use constructor 21 return 0; 23 24 } // end main 25 fig22_11.cpp (1 of 2) This call will cause an error when compiled.

29 fig22_11.cpp (2 of 2) fig22_11.cpp output (1 of 1)
26 // display array contents 27 void outputArray( const Array &arrayToOutput ) 28 { cout << "The array received contains:\n" << arrayToOutput << "\n\n"; 31 32 } // end outputArray fig22_11.cpp (2 of 2) fig22_11.cpp output (1 of 1) 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 ambiguous Error executing cl.exe. test.exe - 1 error(s), 0 warning(s)

30 22.7 mutable Class Members mutable data member const_cast vs. mutable
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

31 Declare a mutable int. It can be modified by const functions.
// Fig : fig21_12.cpp // Demonstrating storage class specifier mutable. #include <iostream> 4 using std::cout; using std::endl; 7 // class TestMutable definition class TestMutable { 10 public: TestMutable( int v = 0 ) { value = v; } void modifyValue() const { value++; } int getValue() const { return value; } 14 private: mutable int value; // mutable member 16 17 }; // end class TestMutable 18 19 int main() 20 { const TestMutable test( 99 ); 22 cout << "Initial value: " << test.getValue(); 24 test.modifyValue(); // modifies mutable member cout << "\nModified value: " << test.getValue() << endl; fig21_12.cpp (1 of 2) Declare a mutable int. It can be modified by const functions.

32 fig21_12.cpp (2 of 2) fig21_12.cpp output (1 of 1)
27 return 0; 29 30 } // end main fig21_12.cpp (2 of 2) fig21_12.cpp output (1 of 1) Initial value: 99 Modified value: 100

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)()

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

35 fig22_13.cpp (1 of 2) 1 // Fig. 22.13 : fig22_13.cpp
// Demonstrating operators .* and ->*. #include <iostream> 4 using std::cout; using std::endl; 7 // class Test definition class Test { 10 public: void function() { cout << "function\n"; } int value; // public data member 13 }; // end class Test 14 15 void arrowStar( Test * ); 16 void dotStar( Test * ); 17 18 int main() 19 { Test test; 21 test.value = 8; // assign value 8 arrowStar( &test ); // pass address to arrowStar dotStar( &test ); // pass address to dotStar fig22_13.cpp (1 of 2)

36 Next, call function directly.
25 return 0; 27 28 } // end main 29 30 // access member function of Test object using ->* 31 void arrowStar( Test *testPtr ) 32 { // declare function pointer void ( Test::*memPtr )() = &Test::function; 35 // invoke function indirectly ( testPtr->*memPtr )(); 38 39 } // end arrowStar 40 41 // access members of Test object data member using .* 42 void dotStar( Test *testPtr2 ) 43 { int Test::*vPtr = &Test::value; // declare pointer 45 cout << ( *testPtr2 ).*vPtr << endl; // access value 47 48 } // end dotStar fig22_13.cpp (2 of 2) 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.

37 function 8 fig22_13.cpp output (1 of 1)

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 }

39 This base class contains an int.
// Fig. 22.14: base1.h // Definition of class Base1 #ifndef BASE1_H #define BASE1_H 5 // class Base1 definition class Base1 { public: Base1( int parameterValue ) { value = parameterValue; } int getData() const { return value; } 11 12 protected: // accessible to derived classes int value; // inherited by derived class 14 15 }; // end class Base1 16 17 #endif // BASE1_H base1.h (1 of 1) There are two base classes in this example, each has its own getData function. This base class contains an int.

40 base2.h (1 of 1) 1 // Fig. 22.15: base2.h
// Definition of class Base2 #ifndef BASE2_H #define BASE2_H 5 // class Base2 definition class Base2 { public: Base2( char characterData ) { letter = characterData; } char getData() const { return letter; } 11 12 protected: // accessible to derived classes char letter; // inherited by derived class 14 15 }; // end class Base2 16 17 #endif // BASE2_H base2.h (1 of 1)

41 Use comma-separated list.
// Fig. 22.16: derived.h // Definition of class Derived which inherits // multiple base classes (Base1 and Base2). #ifndef DERIVED_H #define DERIVED_H 6 #include <iostream> 8 using std::ostream; 10 11 #include "base1.h" 12 #include "base2.h" 13 14 // class Derived definition 15 class Derived : public Base1, public Base2 { friend ostream &operator<<( ostream &, const Derived & ); 17 18 public: Derived( int, char, double ); double getReal() const; 21 22 private: double real; // derived class's private data 24 25 }; // end class Derived 26 27 #endif // DERIVED_H derived.h (1 of 1) Use comma-separated list.

42 Note use of base-class constructors in derived class constructor.
// Fig. 22.17: derived.cpp // Member function definitions for class Derived #include "derived.h" 4 // constructor for Derived calls constructors for // class Base1 and class Base2. // use member initializers to call base-class constructors Derived::Derived( int integer, char character, double double1 ) : Base1( integer ), Base2( character ), real( double1 ) { } 10 11 // return real 12 double Derived::getReal() const { return real; } 13 14 // display all data members of Derived 15 ostream &operator<<( ostream &output, const Derived &derived ) 16 { output << " Integer: " << derived.value << "\n Character: " << derived.letter << "\nReal number: " << derived.real; 20 return output; // enables cascaded calls 22 23 } // end operator<< Note use of base-class constructors in derived class constructor. derived.cpp (1 of 1)

43 fig22_18.cpp (1 of 2) 1 // Fig. 22.18: fig22_18.cpp
// Driver for multiple inheritance example. #include <iostream> 4 using std::cout; using std::endl; 7 #include "base1.h" #include "base2.h" 10 #include "derived.h" 11 12 int main() 13 { Base1 base1( 10 ), *base1Ptr = 0; // create Base1 object Base2 base2( 'Z' ), *base2Ptr = 0; // create Base2 object Derived derived( 7, 'A', 3.5 ); // create Derived object 17 // print data members of base-class objects cout << "Object base1 contains integer " << base1.getData() << "\nObject base2 contains character " << base2.getData() << "\nObject derived contains:\n" << derived << "\n\n"; 24 fig22_18.cpp (1 of 2)

44 Note calls to specific base class functions.
// print data members of derived-class object // scope resolution operator resolves getData ambiguity cout << "Data members of Derived can be" << " accessed individually:" << "\n Integer: " << derived.Base1::getData() << "\n Character: " << derived.Base2::getData() << "\nReal number: " << derived.getReal() << "\n\n"; 32 cout << "Derived can be treated as an " << "object of either base class:\n"; 35 // treat Derived as a Base1 object base1Ptr = &derived; cout << "base1Ptr->getData() yields " << base1Ptr->getData() << '\n'; 40 // treat Derived as a Base2 object base2Ptr = &derived; cout << "base2Ptr->getData() yields " << base2Ptr->getData() << endl; 45 return 0; 47 48 } // end main fig22_18.cpp (2 of 2) Note calls to specific base class functions. Can treat derived-class pointer as either base-class pointer.

45 fig22_18.cpp output (1 of 1) Object base1 contains integer 10
Object base2 contains character Z Object derived contains: Integer: 7 Character: A Real number: 3.5 Data members of Derived can be accessed individually: Derived can be treated as an object of either base class: base1Ptr->getData() yields 7 base2Ptr->getData() yields A fig22_18.cpp output (1 of 1)

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 ostream istream iostream

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

48 This example will demonstrate the ambiguity of multiple inheritance.
// Fig. 22.20: fig22_20.cpp // Attempting to polymorphically call a function that is // multiply inherited from two base classes. #include <iostream> 5 using std::cout; using std::endl; 8 // class Base definition 10 class Base { 11 public: virtual void print() const = 0; // pure virtual 13 14 }; // end class Base 15 16 // class DerivedOne definition 17 class DerivedOne : public Base { 18 public: 19 // override print function void print() const { cout << "DerivedOne\n"; } 22 23 }; // end class DerivedOne 24 fig22_20.cpp (1 of 3) This example will demonstrate the ambiguity of multiple inheritance.

49 fig22_20.cpp (2 of 3) 25 // class DerivedTwo definition
26 class DerivedTwo : public Base { 27 public: 28 // override print function void print() const { cout << "DerivedTwo\n"; } 31 32 }; // end class DerivedTwo 33 34 // class Multiple definition 35 class Multiple : public DerivedOne, public DerivedTwo { 36 public: 37 // qualify which version of function print void print() const { DerivedTwo::print(); } 40 41 }; // end class Multiple 42 fig22_20.cpp (2 of 3)

50 Which base subobject will be used?
43 int main() 44 { Multiple both; // instantiate Multiple object DerivedOne one; // instantiate DerivedOne object DerivedTwo two; // instantiate DerivedTwo object 48 // create array of base-class pointers Base *array[ 3 ]; 51 array[ 0 ] = &both; // ERROR--ambiguous array[ 1 ] = &one; array[ 2 ] = &two; 55 // polymorphically invoke print for ( int i = 0; i < 3; i++ ) array[ i ] -> print(); 59 return 0; 61 62 } // end main fig22_20.cpp (3 of 3) Which base subobject will be used?

51 c:\cpp4e\ch22\fig22_20_21\fig22_20
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) fig22_20.cpp output (1 of 1)

52 Use virtual inheritance to solve the ambiguity problem.
// Fig : fig22_21.cpp // Using virtual base classes. #include <iostream> 4 using std::cout; using std::endl; 7 // class Base definition class Base { 10 public: 11 // implicit default constructor 13 virtual void print() const = 0; // pure virtual 15 16 }; // end Base class 17 18 // class DerivedOne definition 19 class DerivedOne : virtual public Base { 20 public: 21 // implicit default constructor calls // Base default constructor 24 // override print function void print() const { cout << "DerivedOne\n"; } 27 28 }; // end DerivedOne class fig22_21.cpp (1 of 3) Use virtual inheritance to solve the ambiguity problem. The compiler generates default constructors, which greatly simplifies the hierarchy.

53 Use virtual inheritance, as before. fig22_21.cpp (2 of 3)
29 30 // class DerivedTwo definition 31 class DerivedTwo : virtual public Base { 32 public: 33 // implicit default constructor calls // Base default constructor 36 // override print function void print() const { cout << "DerivedTwo\n"; } 39 40 }; // end DerivedTwo class 41 42 // class Multiple definition 43 class Multiple : public DerivedOne, public DerivedTwo { 44 public: 45 // implicit default constructor calls // DerivedOne and DerivedTwo default constructors 48 // qualify which version of function print void print() const { DerivedTwo::print(); } 51 52 }; // end Multiple class Use virtual inheritance, as before. fig22_21.cpp (2 of 3)

54 fig22_21.cpp (3 of 3) 53 54 int main() 55 {
55 { Multiple both; // instantiate Multiple object DerivedOne one; // instantiate DerivedOne object DerivedTwo two; // instantiate DerivedTwo object 59 // declare array of base-class pointers and initialize // each element to a derived-class type Base *array[ 3 ]; 63 array[ 0 ] = &both; array[ 1 ] = &one; array[ 2 ] = &two; 67 // polymorphically invoke function print for ( int i = 0; i < 3; i++ ) array[ i ]->print(); 71 return 0; 73 74 } // end main fig22_21.cpp (3 of 3)

55 DerivedTwo DerivedOne
fig22_21.cpp output (1 of 1)


Download ppt "Chapter 22 - Other Topics Outline 22.1 Introduction"

Similar presentations


Ads by Google