1 / 55

Chapter 22 - Other Topics

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

khaggard
Télécharger la présentation

Chapter 22 - Other Topics

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  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

  2. 22.1 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. 1 // Fig. 22.1: fig22_01.cpp 2 // Demonstrating operator const_cast. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 // class ConstCastTest definition 9 class ConstCastTest { 10 public: 11 void setNumber( int ); 12 int getNumber() const; 13 void printNumber() const; 14 private: 15 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 Function is const, and cannot modify data. fig22_01.cpp(1 of 2)

  5. 24 // output number 25 void ConstCastTest::printNumber() const 26 { 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 printNumber 35 36 int main() 37 { 38 ConstCastTest test; // create ConstCastTest instance 39 40 test.setNumber( 8 ); // set private data number to 8 41 42 cout << "Initial value of number: " << test.getNumber(); 43 44 test.printNumber(); 45 return0; 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.cppoutput (1 of 1) Initial value of number: 8 Number after modification: 7

  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)

  7. 1 // Fig. 22.2: fig22_02.cpp 2 // 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 return0; 17 18 } // end main Create an int *. Cast it to a char * for printing. 120 is the ASCII value of 'x'. fig22_02.cpp(1 of 1)fig22_02.cppoutput (1 of 1) x

  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

  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. 1 // Fig. 22.3: fig22_03.cpp 2 // Demonstrating namespaces. 3 #include <iostream> 4 5 using namespace std; // use std namespace 6 7 int integer1 = 98; // global variable 8 9 // create namespace Example 10 namespace Example { 11 12 // declare two constants and one variable 13 const doublePI = 3.14159; 14 const doubleE = 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. Create a new namespace, Example. Note that it has a variable integer1, different from the global integer1. Note the nested namespace Inner. fig22_03.cpp(1 of 3)

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

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

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

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

  15. 22.5 Operator Keywords

  16. 1 // Fig. 22.5: fig22_05.cpp 2 // 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. fig22_05.cpp(1 of 2)

  17. 28 29 return0; 30 31 } // end main fig22_05.cpp(2 of 2)fig22_05.cppoutput (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. 1 // Fig 22.6: array.h 2 // Simple class Array (for integers). 3 #ifndef ARRAY_H 4 #define ARRAY_H 5 6 #include <iostream> 7 8 using std::ostream; 9 10 // class Array definition 11 class Array { 12 friend ostream &operator<<( ostream &, const Array & ); 13 public: 14 Array( int = 10 ); // default/conversion constructor 15 ~Array(); // destructor 16 private: 17 int size; // size of the array 18 int *ptr; // pointer to first element of array 19 20 }; // end class Array 21 22 #endif// ARRAY_H Without the explicit keyword, this constructor can be used for implicit conversions. array.h (1 of 1)

  21. 1 // Fig 22.7: array.cpp 2 // 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 array 20 ptr = newint[ size ]; 21 22 // initialize array elements to zeroes 23 for ( int i = 0; i < size; i++ ) 24 ptr[ i ] = 0; 25 26 } // end constructor array.cpp (1 of 2)

  22. 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 { 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<< array.cpp (2 of 2)

  23. 1 // Fig 22.8: fig22_08.cpp 2 // 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 integers1 16 17 outputArray( 15 ); // convert 15 to an Array and output 18 19 return0; 20 21 } // end main Call outputArray and pass an int. This works because the int is implicitly converted to an Array by the constructor. fig22_08.cpp(1 of 2)

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

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

  26. 1 // Fig. 22.10: array.cpp 2 // 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 array 20 ptr = newint[ size ]; 21 22 // initialize array elements to zeroes 23 for ( int i = 0; i < size; i++ ) 24 ptr[ i ] = 0; 25 26 } // end constructor array.cpp (1 of 2)

  27. 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 { 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<< array.cpp (2 of 2)

  28. 1 // Fig. 22.11: fig22_11.cpp 2 // 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 integers1 16 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 return0; 23 24 } // end main 25 This call will cause an error when compiled. fig22_11.cpp(1 of 2)

  29. 26 // display array contents 27 void outputArray( const Array &arrayToOutput ) 28 { 29 cout << "The array received contains:\n" 30 << arrayToOutput << "\n\n"; 31 32 } // end outputArray fig22_11.cpp(2 of 2)fig22_11.cppoutput (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 • 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. 1 // Fig. 21.12: fig21_12.cpp 2 // Demonstrating storage class specifier mutable. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 // class TestMutable definition 9 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 mutableint value; // mutable member 16 17 }; // end class TestMutable 18 19 int main() 20 { 21 const TestMutable test( 99 ); 22 23 cout << "Initial value: " << test.getValue(); 24 25 test.modifyValue(); // modifies mutable member 26 cout << "\nModified value: " << test.getValue() << endl; Declare a mutable int. It can be modified by const functions. fig21_12.cpp(1 of 2)

  32. 27 28 return0; 29 30 } // end main fig21_12.cpp(2 of 2)fig21_12.cppoutput (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. 1 // Fig. 22.13 : fig22_13.cpp 2 // Demonstrating operators .* and ->*. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 // class Test definition 9 class Test { 10 public: 11 void function() { cout << "function\n"; } 12 int value; // public data member 13 }; // end class Test 14 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 arrowStar 24 dotStar( &test ); // pass address to dotStar fig22_13.cpp(1 of 2)

  36. 25 26 return0; 27 28 } // end main 29 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 indirectly 37 ( testPtr->*memPtr )(); 38 39 } // end arrowStar 40 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 value 47 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. fig22_13.cpp(2 of 2)

  37. function 8 fig22_13.cppoutput (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. 1 // Fig. 22.14: base1.h 2 // Definition of class Base1 3 #ifndef BASE1_H 4 #define BASE1_H 5 6 // class Base1 definition 7 class Base1 { 8 public: 9 Base1( int parameterValue ) { value = parameterValue; } 10 int getData() const { return value; } 11 12 protected: // accessible to derived classes 13 int value; // inherited by derived class 14 15 }; // end class Base1 16 17 #endif// BASE1_H There are two base classes in this example, each has its own getData function. This base class contains an int. base1.h (1 of 1)

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

  41. 1 // Fig. 22.16: derived.h 2 // Definition of class Derived which inherits 3 // multiple base classes (Base1 and Base2). 4 #ifndef DERIVED_H 5 #define DERIVED_H 6 7 #include <iostream> 8 9 using std::ostream; 10 11 #include"base1.h" 12 #include"base2.h" 13 14 // class Derived definition 15 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 data 24 25 }; // end class Derived 26 27 #endif// DERIVED_H Use comma-separated list. derived.h (1 of 1)

  42. 1 // Fig. 22.17: derived.cpp 2 // Member function definitions for class Derived 3 #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 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 { 17 output << " Integer: " << derived.value 18 << "\n Character: " << derived.letter 19 << "\nReal number: " << derived.real; 20 21 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. 1 // Fig. 22.18: fig22_18.cpp 2 // 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 object 15 Base2 base2( 'Z' ), *base2Ptr = 0; // create Base2 object 16 Derived derived( 7, 'A', 3.5 ); // create Derived object 17 18 // print data members of base-class objects 19 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 fig22_18.cpp(1 of 2)

  44. 25 // print data members of derived-class object 26 // scope resolution operator resolves getData ambiguity 27 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 object 37 base1Ptr = &derived; 38 cout << "base1Ptr->getData() yields " 39 << base1Ptr->getData() << '\n'; 40 41 // treat Derived as a Base2 object 42 base2Ptr = &derived; 43 cout << "base2Ptr->getData() yields " 44 << base2Ptr->getData() << endl; 45 46 return0; 47 48 } // end main Note calls to specific base class functions. Can treat derived-class pointer as either base-class pointer. fig22_18.cpp(2 of 2)

  45. 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: Integer: 7 Character: A Real number: 3.5 Derived can be treated as an object of either base class: base1Ptr->getData() yields 7 base2Ptr->getData() yields A fig22_18.cppoutput (1 of 1)

  46. ios ostream istream iostream 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

  47. Base Class virtual inheritance virtual inheritance First Derived Class Second Derived Class Multiply-Derived Class 22.10 Multiple Inheritance and virtual Base Classes • Solution: use virtual base class inheritance • Only one subobject inherited into multiply derived class

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

  49. 25 // class DerivedTwo definition 26 class DerivedTwo : public Base { 27 public: 28 29 // override print function 30 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 38 // qualify which version of function print 39 void print() const { DerivedTwo::print(); } 40 41 }; // end class Multiple 42 fig22_20.cpp(2 of 3)

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

More Related