Você está na página 1de 55

1

Chapter 22 - Other Topics


Outline 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 22.10 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

2003 Prentice Hall, Inc. All rights reserved.

22.1 Introduction Consider additional C++ features


Cast operators Namespaces Operator keywords Multiple inheritence

2003 Prentice Hall, Inc. All rights reserved.

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 >

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

// Fig. 22.1: fig22_01.cpp // Demonstrating operator const_cast. #include <iostream> using std::cout; using std::endl; // class ConstCastTest definition class ConstCastTest { public: void setNumber( int ); int getNumber() const; void printNumber() const; private: int number; }; // end class ConstCastTest

Outline
fig22_01.cpp (1 of 2)

Function is const, and cannot modify data.

// set number void ConstCastTest::setNumber( int num ) { number = num; } // return number int ConstCastTest::getNumber() const { return number; }

2003 Prentice Hall, Inc.


All rights reserved.

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

// output number void ConstCastTest::printNumber() const { cout << "\nNumber after modification: "; // cast away const-ness to allow modification const_cast< ConstCastTest * >( this )->number--; cout << number << endl; } // end printNumber

Outline
Cast away the const-ness fig22_01.cpp the this pointer. This allows (2 of 2) the data to be modified. fig22_01.cpp output (1 of 1)

int main() { ConstCastTest test; test.setNumber( 8 );

// create ConstCastTest instance // set private data number to 8

cout << "Initial value of number: " << test.getNumber(); test.printNumber(); return 0; } // end main

Initial value of number: 8 Number after modification: 7

2003 Prentice Hall, Inc.


All rights reserved.

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)

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 x

// Fig. 22.2: fig22_02.cpp // Demonstrating operator reinterpret_cast. #include <iostream> using std::cout; using std::endl; int main() { int x = 120; int *ptr = &x;

Outline
fig22_02.cpp (1 of 1)

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

fig22_02.cpp output (1 of 1)

// use reinterpret_cast to cast from int * to char * cout << *reinterpret_cast< char * >( ptr ) << endl; return 0; } // end main

2003 Prentice Hall, Inc.


All rights reserved.

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


2003 Prentice Hall, Inc. All rights reserved.

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

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

// Fig. 22.3: fig22_03.cpp // Demonstrating namespaces. #include <iostream> using namespace std; int integer1 = 98; // use std

10

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

Outline
fig22_03.cpp (1 of 3)

// global variable

// create namespace Example namespace Example { // declare two constants and one const double PI = 3.14159; const double E = 2.71828; int integer1 = 8; void printValues(); // nested namespace namespace Inner {

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

// prototype Note

the nested namespace Inner.

// define enumeration enum Years { FISCAL1 = 1990, FISCAL2, FISCAL3 }; } } // end Inner

// end Example

2003 Prentice Hall, Inc.


All rights reserved.

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

11
// create unnamed namespace namespace { double doubleInUnnamed = 88.22; } // end unnamed namespace

// declare

Create an unnamed Outline namespace. Its variables are global. variable fig22_03.cpp (2 of 3)

int main() { // output value doubleInUnnamed of unnamed namespace cout << "doubleInUnnamed = " << doubleInUnnamed; // output global variable cout << "\n(global) integer1 = " << integer1; // output values of Example namespace cout << "\nPI = " << Example::PI << "\nE = " << Example::E << "\ninteger1 = " << Example::integer1 << "\nFISCAL3 = " << Example::Inner::FISCAL3 << endl; Example::printValues(); return 0; } // end main // invoke printValues function

2003 Prentice Hall, Inc.


All rights reserved.

54 55 56 57 58 59 60 61 62 63 64

12
// display variable and constant values void Example::printValues() { cout << "\nIn printValues:\ninteger1 = " << integer1 << "\nPI = " << PI << "\nE = " << E << "\ndoubleInUnnamed = " << doubleInUnnamed << "\n(global) integer1 = " << ::integer1 << "\nFISCAL3 = " << Inner::FISCAL3 << endl; } // end printValues

Outline
fig22_03.cpp (3 of 3)

2003 Prentice Hall, Inc.


All rights reserved.

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

13

Outline
fig22_03.cpp output (1 of 1)

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.

2003 Prentice Hall, Inc. All rights reserved.

15

22.5 Operator Keywords


Operator Logical operator keywords && || ! Inequality operator keyword != Bitwise operator keywords & | ^ ~ Bitwise assignment operator keywords &= |= ^= Operator keyword and or not Description logical AND logical OR logical NOT

not_eq

Inequality

bitand bitor xor compl

Bitwise Bitwise Bitwise Bitwise

AND inclusive OR exclusive OR complement

and_eq or_eq xor_eq

Bitwise AND assignment Bitwise inclusive OR assignment Bitwise exclusive OR assignment

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

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

16

Outline
fig22_05.cpp (1 of 2)

Note use of operator keywords.


b: b: a: b: b: b: b: a: b: b: b: " " " " " " " " " " " << << << << << << << << << << << ( ( ( ( ( ( ( ( ( ( ( a and b ) a or b ) not a ) a not_eq b ) a bitand b ) a bitor b ) a xor b ) compl a ) a and_eq b ) a or_eq b ) a xor_eq b ) << endl;

2003 Prentice Hall, Inc.


All rights reserved.

28 29 30 31

17
return 0; } // end main

Outline
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

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

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

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

// Fig 22.6: array.h // Simple class Array (for integers). #ifndef ARRAY_H #define ARRAY_H #include <iostream> using std::ostream;

20

Outline
array.h (1 of 1)

// class Array definition Without the explicit class Array { this constructor friend ostream &operator<<( ostreamkeyword, &, const Array & ); be used for implicit public: Array( int = 10 ); // default/conversion constructor conversions. ~Array(); // destructor private: int size; // size of the array int *ptr; // pointer to first element of array
}; // end class Array // ARRAY_H

can

#endif

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Fig 22.7: array.cpp // Member function definitions for class Array. #include <iostream> using std::cout; using std::ostream; #include <new>

21

Outline
array.cpp (1 of 2)

#include "array.h"
// default constructor for class Array (default size 10) Array::Array( int arraySize ) { size = ( arraySize < 0 ? 10 : arraySize ); cout << "Array constructor called for " << size << " elements\n"; // create space for array ptr = new int[ size ]; // initialize array elements to zeroes for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; } // end constructor

2003 Prentice Hall, Inc.


All rights reserved.

27 28 29 30 31 32 33 34 35 36 37 38 39

22
// destructor for class Array Array::~Array() { delete [] ptr; } // overloaded stream insertion operator for class Array ostream &operator<<( ostream &output, const Array &arrayRef ) { for ( int i = 0; i < arrayRef.size; i++ ) output << arrayRef.ptr[ i ] << ' ' ; return output; } // end operator<< // enables cout << x << y;

Outline
array.cpp (2 of 2)

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

// Fig 22.8: fig22_08.cpp // Driver for simple class Array. #include <iostream> using std::cout; #include "array.h" void outputArray( const Array & ); int main() { Array integers1( 7 ); outputArray( integers1 ); outputArray( 15 ); return 0; } // end main //

23

Outline
fig22_08.cpp (1 of 2)

// convert

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

2003 Prentice Hall, Inc.


All rights reserved.

22 23 24 25 26 27 28 29

24
// print array contents void outputArray( const Array &arrayToOutput ) { cout << "The array received contains:\n" << arrayToOutput << "\n\n"; } // end outputArray

Outline
fig22_08.cpp (2 of 2) fig22_08.cpp output (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

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

// Fig. 22.9: array.h // Simple class Array (for integers). #ifndef ARRAY_H #define ARRAY_H #include <iostream> using std::ostream;

25

Outline
array.h (1 of 1)

// class Array definition This time, declare constructor class Array { friend ostream &operator<<( ostream explicit &, const Array & ); . public: explicit Array( int = 10 ); // default constructor ~Array(); // destructor private: int size; // size of the array int *ptr; // pointer to first element of array
}; // end class Array // ARRAY_H

#endif

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Fig. 22.10: array.cpp // Member function definitions for class Array. #include <iostream> using std::cout; using std::ostream; #include <new>

26

Outline
array.cpp (1 of 2)

#include "array.h"
// default constructor for class Array (default size 10) Array::Array( int arraySize ) { size = ( arraySize < 0 ? 10 : arraySize ); cout << "Array constructor called for " << size << " elements\n"; // create space for array ptr = new int[ size ]; // initialize array elements to zeroes for ( int i = 0; i < size; i++ ) ptr[ i ] = 0; } // end constructor

2003 Prentice Hall, Inc.


All rights reserved.

27 28 29 30 31 32 33 34 35 36 37 38 39

27
// destructor for class Array Array::~Array() { delete [] ptr; } // overloaded insertion operator for class Array ostream &operator<<( ostream &output, const Array &arrayRef ) { for ( int i = 0; i < arrayRef.size; i++ ) output << arrayRef.ptr[ i ] << ' ' ; return output; } // end operator<< // enables cout << x << y;

Outline
array.cpp (2 of 2)

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

// Fig. 22.11: fig22_11.cpp // Driver for simple class Array. #include <iostream> using std::cout; #include "array.h" void outputArray( const Array & ); int main() { Array integers1( 7 ); outputArray( integers1 ); // output Array integers1

28

Outline
fig22_11.cpp (1 of 2)

// ERROR: construction not allowed outputArray( 15 ); // convert 15 to an Array and output outputArray( Array( 15 ) ); // must use constructor return 0; } // end main

This call will cause an error when compiled.

2003 Prentice Hall, Inc.


All rights reserved.

26 27 28 29 30 31 32

// display array contents void outputArray( const Array &arrayToOutput ) { cout << "The array received contains:\n" << arrayToOutput << "\n\n"; } // end outputArray

29

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

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

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

// Fig. 21.12: fig21_12.cpp // Demonstrating storage class specifier mutable. #include <iostream> using std::cout; using std::endl;

31

Outline
fig21_12.cpp (1 of 2)

// class TestMutable definition class TestMutable { public: TestMutable( int v = 0 ) { value = v; } void modifyValue() const { value++; } int getValue() const { return value; } private: mutable int value; // mutable member }; // end class TestMutable

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

int main() { const TestMutable test( 99 );

cout << "Initial value: " << test.getValue();


test.modifyValue(); // modifies mutable member cout << "\nModified value: " << test.getValue() << endl;

2003 Prentice Hall, Inc.


All rights reserved.

27 28 29 30

32
return 0; } // end main

Outline
fig21_12.cpp (2 of 2) fig21_12.cpp output (1 of 1)

Initial value: 99 Modified value: 100

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

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

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

// Fig. 22.13 : fig22_13.cpp // Demonstrating operators .* and ->*. #include <iostream> using std::cout; using std::endl; // class Test definition class Test { public: void function() { cout << "function\n"; } int value; // public data member }; // end class Test void arrowStar( Test * ); void dotStar( Test * ); int main() { Test test; test.value = 8; arrowStar( &test ); dotStar( &test ); // assign value 8 // pass address to arrowStar // pass address to dotStar

35

Outline
fig22_13.cpp (1 of 2)

2003 Prentice Hall, Inc.


All rights reserved.

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

36
return 0; } // end main

Outline
fig22_13.cpp (2 of 2)

// access member function of Test object using ->* Assign function pointer to the void arrowStar( Test *testPtr ) { address of function in // declare function pointer Test. Note that neither side void ( Test::*memPtr )() = &Test::function; refers to a specific object. // invoke function indirectly ( testPtr->*memPtr )(); } // end arrowStar

Next, call function directly.

Create // access members of Test object data member using .* pointer to data member value. Then, access the void dotStar( Test *testPtr2 ) { data. int Test::*vPtr = &Test::value; // declare pointer
cout << ( *testPtr2 ).*vPtr << endl; } // end dotStar // access value

2003 Prentice Hall, Inc.


All rights reserved.

function 8

37

Outline
fig22_13.cpp output (1 of 1)

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 }

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

// Fig. 22.14: base1.h // Definition of class Base1 #ifndef BASE1_H #define BASE1_H

39

Outline
base1.h (1 of 1)

// class Base1 definition class Base1 { There are two base classes in public: this example, each has its own Base1( int parameterValue ) { value = parameterValue; } getData function. int getData() const { return value; } protected: int value; }; // accessible to derived classes // inherited by derived class

This base class contains an int.

// end class Base1 // BASE1_H

#endif

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

// Fig. 22.15: base2.h // Definition of class Base2 #ifndef BASE2_H #define BASE2_H // class Base2 definition class Base2 { public: Base2( char characterData ) { letter = characterData; } char getData() const { return letter; } protected: char letter; }; // accessible to derived classes // inherited by derived class

40

Outline
base2.h (1 of 1)

// end class Base2 // BASE2_H

#endif

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

// Fig. 22.16: derived.h // Definition of class Derived which inherits // multiple base classes (Base1 and Base2). #ifndef DERIVED_H #define DERIVED_H #include <iostream> using std::ostream; #include "base1.h" #include "base2.h"

41

Outline
derived.h (1 of 1)

Use comma-separated list.

// class Derived definition class Derived : public Base1, public Base2 { friend ostream &operator<<( ostream &, const Derived & ); public: Derived( int, char, double ); double getReal() const; private: double real; };

// derived class's private data

// end class Derived // DERIVED_H

#endif

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

// Fig. 22.17: derived.cpp // Member function definitions for class Derived #include "derived.h"

42

Outline
Note use of base-class constructors in derived class derived.cpp (1 of 1) constructor.

// 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 ) { } // return real double Derived::getReal() const { return real; } // display all data members of Derived ostream &operator<<( ostream &output, const Derived &derived ) { output << " Integer: " << derived.value << "\n Character: " << derived.letter << "\nReal number: " << derived.real; return output; // enables cascaded calls

// end operator<<

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

// Fig. 22.18: fig22_18.cpp // Driver for multiple inheritance example. #include <iostream> using std::cout; using std::endl; #include "base1.h" #include "base2.h" #include "derived.h" int main() { 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 // 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";

43

Outline
fig22_18.cpp (1 of 2)

2003 Prentice Hall, Inc.


All rights reserved.

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

// 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"; cout << "Derived can be treated as an " << "object of either base class:\n"; // treat Derived as a Base1 object base1Ptr = &derived; cout << "base1Ptr->getData() yields " << base1Ptr->getData() << '\n'; // treat Derived as a Base2 object base2Ptr = &derived; cout << "base2Ptr->getData() yields " << base2Ptr->getData() << endl; return 0; } // end main

44

Outline
fig22_18.cpp (2 of 2)

Note calls to specific base class functions.

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

2003 Prentice Hall, Inc.


All rights reserved.

Object base1 contains integer 10 Object base2 contains character Z Object derived contains: Integer: 7 Character: A Real number: 3.5 Data members Integer: Character: Real number: of Derived can be accessed individually: 7 A 3.5

45

Outline
fig22_18.cpp output (1 of 1)

Derived can be treated as an object of either base class: base1Ptr->getData() yields 7 base2Ptr->getData() yields A

2003 Prentice Hall, Inc.


All rights reserved.

46

22.10 Multiple Inheritance and virtual Base Classes Ambiguities from multiple inheritance
ios istream iostream ostream

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

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
Base Class virtual inheritance First Derived Class
virtual inheritance

Second Derived Class

Multiply-Derived Class

2003 Prentice Hall, Inc. All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

// Fig. 22.20: fig22_20.cpp // Attempting to polymorphically call a function that is // multiply inherited from two base classes. #include <iostream> using std::cout; using std::endl;

48

Outline
fig22_20.cpp (1 of 3)

// class Base definition class Base { public: virtual void print() const = 0; }; // end class Base

This example will demonstrate the ambiguity of multiple inheritance.


// pure virtual

// class DerivedOne definition class DerivedOne : public Base { public: // override print function void print() const { cout << "DerivedOne\n"; }

};

// end class DerivedOne

2003 Prentice Hall, Inc.


All rights reserved.

25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

// class DerivedTwo definition class DerivedTwo : public Base { public: // override print function void print() const { cout << "DerivedTwo\n"; } }; // end class DerivedTwo

49

Outline
fig22_20.cpp (2 of 3)

// class Multiple definition class Multiple : public DerivedOne, public DerivedTwo { public:
// qualify which version of function print void print() const { DerivedTwo::print(); } }; // end class Multiple

2003 Prentice Hall, Inc.


All rights reserved.

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

int main() { Multiple both; DerivedOne one; DerivedTwo two;

50

Outline
// instantiate Multiple object // instantiate DerivedOne object // instantiate DerivedTwo object

fig22_20.cpp (3 of 3)

// create array of base-class pointers Which Base *array[ 3 ];

base subobject will be

used?

array[ 0 ] = &both; array[ 1 ] = &one; array[ 2 ] = &two;

// ERROR--ambiguous

// polymorphically invoke print for ( int i = 0; i < 3; i++ ) array[ i ] -> print(); return 0; } // end main

2003 Prentice Hall, Inc.


All rights reserved.

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)

51

Outline
fig22_20.cpp output (1 of 1)

2003 Prentice Hall, Inc.


All rights reserved.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

// Fig. 22.21: fig22_21.cpp // Using virtual base classes. #include <iostream> using std::cout; using std::endl; // class Base definition class Base { public: // implicit default constructor virtual void print() const = 0; // pure virtual }; // end Base class

52

Outline
fig22_21.cpp (1 of 3)

// class DerivedOne definition class DerivedOne : virtual public Base { public: // implicit default constructor calls // Base default constructor

Use virtual inheritance to solve the ambiguity problem.


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

// override print function void print() const { cout << "DerivedOne\n"; } }; // end DerivedOne class

2003 Prentice Hall, Inc.


All rights reserved.

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

53
// class DerivedTwo definition class DerivedTwo : virtual public Base { public: // implicit default constructor calls // Base default constructor

Outline
fig22_21.cpp (2 of 3)

Use virtual inheritance, as before.

// override print function void print() const { cout << "DerivedTwo\n"; } }; // end DerivedTwo class // class Multiple definition class Multiple : public DerivedOne, public DerivedTwo { public: // implicit default constructor calls // DerivedOne and DerivedTwo default constructors // qualify which version of function print void print() const { DerivedTwo::print(); } }; // end Multiple class

2003 Prentice Hall, Inc.


All rights reserved.

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74

54
int main() { Multiple both; DerivedOne one; DerivedTwo two;

Outline
// instantiate Multiple object // instantiate DerivedOne object // instantiate DerivedTwo object

fig22_21.cpp (3 of 3)

// declare array of base-class pointers and initialize // each element to a derived-class type Base *array[ 3 ]; array[ 0 ] = &both; array[ 1 ] = &one; array[ 2 ] = &two; // polymorphically invoke function print for ( int i = 0; i < 3; i++ ) array[ i ]->print(); return 0; } // end main

2003 Prentice Hall, Inc.


All rights reserved.

DerivedTwo DerivedOne DerivedTwo

55

Outline
fig22_21.cpp output (1 of 1)

2003 Prentice Hall, Inc.


All rights reserved.

Você também pode gostar