Other Topics

57
1 2006 Pearson Education, Inc. All rights rese 2 4 Other Topics

description

24. Other Topics. What's in a name? that which we call a rose By any other name would smell as sweet. William Shakespeare O Diamond! Diamond! thou little knowest the mischief done! Sir Isaac Newton. OBJECTIVES. In this chapter you will learn: - PowerPoint PPT Presentation

Transcript of Other Topics

1

2006 Pearson Education, Inc. All rights reserved.

2424

Other Topics

2

2006 Pearson Education, Inc. All rights reserved.

What's in a name? that which we call a rose By any other name would smell as sweet.

—William Shakespeare

O Diamond! Diamond! thou little knowest the mischief done!

—Sir Isaac Newton

3

2006 Pearson Education, Inc. All rights reserved.

OBJECTIVES

In this chapter you will learn: To use const_cast to temporarily treat a const

object as a non-const object. To use namespaces. To use operator keywords. To use mutable members in const objects. To use class-member pointer operators .* and ->*. To use multiple inheritance. The role of virtual base classes in multiple

inheritance.

4

2006 Pearson Education, Inc. All rights reserved.

24.1 Introduction

24.2 const_cast Operator

24.3 namespaces

24.4 Operator Keywords

24.5 mutable Class Members

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

24.7 Multiple Inheritance

24.8 Multiple Inheritance and virtual Base Classes

24.9 Wrap-Up

24.10 Closing Remarks

5

2006 Pearson Education, Inc. All rights reserved.

24.1 Introduction

• Advanced C++ features– const_cast operator

• Allows programmers to add or remove const qualifications

– namespaces• Used to ensure that every identifier has a unique name

• Resolve naming conflicts among multiple libraries

– Operator keywords• Useful for keyboards that do not support certain characters

6

2006 Pearson Education, Inc. All rights reserved.

24.1 Introduction (Cont.)

• Advanced C++ features (Cont.)– mutable storage-class specifier

• Indicates a data member should always be modifiable

– Even inside a const object

– .* and ->* operators• Used with pointers to class members

– Multiple inheritance• A derived class inherits from several base classes

• virtual inheritance solves potential problems

7

2006 Pearson Education, Inc. All rights reserved.

24.2 const_cast Operator

•volatile qualifier– Applied to a variable when it is expected to be modified by

hardware or other programs• Indicates that compiler should not optimize this variable

•const_cast operator– Casts away const or volatile qualifications

• In case of const, the variable can now be modified

– Dangerous, but useful in certain situations• Older C and C++ library functions have non-const

parameters but do not actually modify them

• A function could return const data that the programmer knows was originally and should now be non-const

8

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.1: fig24_01.cpp

2 // Demonstrating const_cast.

3 #include <iostream>

4 using std::cout;

5 using std::endl;

6

7 #include <cstring> // contains prototypes for functions strcmp and strlen

8 #include <cctype> // contains prototype for function toupper

9

10 // returns the larger of two C-style strings

11 const char *maximum( const char *first, const char *second )

12 {

13 return ( strcmp( first, second ) >= 0 ? first : second );

14 } // end function maximum

Outline

fig24_01.cpp

(1 of 2)

Function maximum takes two const char * parameters and returns a const char *

9

2006 Pearson Education, Inc. All rights reserved.

15

16 int main()

17 {

18 char s1[] = "hello"; // modifiable array of characters

19 char s2[] = "goodbye"; // modifiable array of characters

20

21 // const_cast required to allow the const char * returned by maximum

22 // to be assigned to the char * variable maxPtr

23 char *maxPtr = const_cast< char * >( maximum( s1, s2 ) );

24

25 cout << "The larger string is: " << maxPtr << endl;

26

27 for ( size_t i = 0; i < strlen( maxPtr ); i++ )

28 maxPtr[ i ] = toupper( maxPtr[ i ] );

29

30 cout << "The larger string capitalized is: " << maxPtr << endl;

31 return 0;

32 } // end main The larger string is: hello The larger string capitalized is: HELLO

Outline

fig24_01.cpp

(2 of 2)

Cast away the const-ness of the pointer returned by maximum

10

2006 Pearson Education, Inc. All rights reserved.

Error-Prevention Tip 24.1

In general, a const_cast should be used only when it is known in advance that the original data is not constant. Otherwise, unexpected results may occur.

11

2006 Pearson Education, Inc. All rights reserved.

24.3 namespaces

• A namespace– Defines scope in which identifiers and variables are placed

• Namespace members

– Qualifying a namespace member’s name• Precede it with the namespace name and the binary scope

resolution operator (::)

– Example

• MyNameSpace::member

12

2006 Pearson Education, Inc. All rights reserved.

Good Programming Practice 24.1

Avoid identifiers that begin with the underscore character, which can lead to linker errors. Many code libraries use names that begin with underscores.

13

2006 Pearson Education, Inc. All rights reserved.

24.3 namespaces (Cont.)

• A namespace (Cont.)– using directives

• Automatically qualifies all members in a namespace• Must appear before the names are used in the program

• Example

– using namespace MyNameSpace;• Members of namespace MyNameSpace can be used

without needing to be qualified

– using declarations• Automatically qualifies one member of a namespace• Example

– using std::cout;• Brings std::cout into the current scope

14

2006 Pearson Education, Inc. All rights reserved.

Software Engineering Observation 24.1

Ideally, in large programs, every entity should be declared in a class, function, block or namespace. This helps clarify every entity’s role.

15

2006 Pearson Education, Inc. All rights reserved.

Error-Prevention Tip 24.2

Precede a member with its namespace name and the scope resolution operator (::) if the possibility exists of a naming conflict.

16

2006 Pearson Education, Inc. All rights reserved.

24.3 namespaces (Cont.)

• Defining namespaces– Keyword namespace

– A namespace name• Can be an unnamed namespace

– Unnamed namespaces have implicit using directives

– Body of a namespace is delimited by braces ({})

– May be defined at global scope or nested within another namespace

• Namespace aliases– Example

• Namespace CPPHTP = CPlusPlusHowToProgram;

– CPPHTP is an alias for CPlusPlusHowToProgram

17

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.2: fig24_02.cpp

2 // Demonstrating namespaces.

3 #include <iostream>

4 using namespace std; // use std namespace

5

6 int integer1 = 98; // global variable

7

8 // create namespace Example

9 namespace Example

10 {

11 // declare two constants and one variable

12 const double PI = 3.14159;

13 const double E = 2.71828;

14 int integer1 = 8;

15

16 void printValues(); // prototype

17

18 // nested namespace

19 namespace Inner

20 {

21 // define enumeration

22 enum Years { FISCAL1 = 1990, FISCAL2, FISCAL3 };

23 } // end Inner namespace

24 } // end Example namespace

Outline

fig24_02.cpp

(1 of 3)

Inform the compiler that namespace std is being used

Define namespace Example

Define variables in namespace Example

Declare a function prototype in namespace Example

Define nested namespace Inner

18

2006 Pearson Education, Inc. All rights reserved.

25

26 // create unnamed namespace

27 namespace

28 {

29 double doubleInUnnamed = 88.22; // declare variable

30 } // end unnamed namespace

31

32 int main()

33 {

34 // output value doubleInUnnamed of unnamed namespace

35 cout << "doubleInUnnamed = " << doubleInUnnamed;

36

37 // output global variable

38 cout << "\n(global) integer1 = " << integer1;

39

40 // output values of Example namespace

41 cout << "\nPI = " << Example::PI << "\nE = " << Example::E

42 << "\ninteger1 = " << Example::integer1 << "\nFISCAL3 = "

43 << Example::Inner::FISCAL3 << endl;

44

45 Example::printValues(); // invoke printValues function

46 return 0;

47 } // end main

Outline

fig24_02.cpp

(2 of 3)

Define an unnamed namespace

doubleInUnnamed is in an unnamed namespace and does not need to be qualified

Output the value of global variable integer1

Qualify variables that are namespace members

19

2006 Pearson Education, Inc. All rights reserved.

48

49 // display variable and constant values

50 void Example::printValues()

51 {

52 cout << "\nIn printValues:\ninteger1 = " << integer1 << "\nPI = "

53 << PI << "\nE = " << E << "\ndoubleInUnnamed = "

54 << doubleInUnnamed << "\n(global) integer1 = " << ::integer1

55 << "\nFISCAL3 = " << Inner::FISCAL3 << endl;

56 } // end printValues 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

Outline

fig24_02.cpp

(3 of 3)

Function printValues of namespace Example can access other members of Example directly

Use the unary scope resolution operator to access global variable integer1

20

2006 Pearson Education, Inc. All rights reserved.

Software Engineering Observation 24.2

Each separate compilation unit has its own unique unnamed namespace; i.e., the unnamed namespace replaces the static linkage specifier.

21

2006 Pearson Education, Inc. All rights reserved.

Common Programming Error 24.1

Placing main in a namespace is a compilation error.

22

2006 Pearson Education, Inc. All rights reserved.

24.4 Operator Keywords

• Operator keywords– Can be used in place of several C++ operators

– Useful for keyboards that do not support certain characters

– Requirements for using operator keywords• Microsoft Visual C++ .NET requires header file <iso646.h>

• GNU C++ requires compiler option –foperator-names• Borland C++ 5.6.4 implicitly permits these keywords

23

2006 Pearson Education, Inc. All rights reserved.

Fig. 24.3 | Operator keyword alternatives to operator symbols.

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

24

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.4: fig24_04.cpp

2 // Demonstrating operator keywords.

3 #include <iostream>

4 using std::boolalpha;

5 using std::cout;

6 using std::endl;

7

8 #include <iso646.h> // enables operator keywords in Microsoft Visual C++

9

10 int main()

11 {

12 bool a = true;

13 bool b = false;

14 int c = 2;

15 int d = 3;

16

17 // sticky setting that causes bool values to display as true or false

18 cout << boolalpha;

19

20 cout << "a = " << a << "; b = " << b

21 << "; c = " << c << "; d = " << d;

22

23 cout << "\n\nLogical operator keywords:";

24 cout << "\n a and a: " << ( a and a );

25 cout << "\n a and b: " << ( a and b );

26 cout << "\n a or a: " << ( a or a );

27 cout << "\n a or b: " << ( a or b );

28 cout << "\n not a: " << ( not a );

29 cout << "\n not b: " << ( not b );

30 cout << "\na not_eq b: " << ( a not_eq b );

Outline

fig24_04.cpp

(1 of 2)

Use the various logical operator keywords

25

2006 Pearson Education, Inc. All rights reserved.

31

32 cout << "\n\nBitwise operator keywords:";

33 cout << "\nc bitand d: " << ( c bitand d );

34 cout << "\nc bit_or d: " << ( c bitor d );

35 cout << "\n c xor d: " << ( c xor d );

36 cout << "\n compl c: " << ( compl c );

37 cout << "\nc and_eq d: " << ( c and_eq d );

38 cout << "\n c or_eq d: " << ( c or_eq d );

39 cout << "\nc xor_eq d: " << ( c xor_eq d ) << endl;

40 return 0;

41 } // end main a = true; b = false; c = 2; d = 3 Logical operator keywords:

a and a: true a and b: false a or a: true a or b: true not a: false not b: true a not_eq b: true Bitwise operator keywords:

c bitand d: 2 c bit_or d: 3 c xor d: 1 compl c: -3 c and_eq d: 2 c or_eq d: 3 c xor_eq d: 0

Outline

fig24_04.cpp

(2 of 2)

Use the various bitwise operator keywords

26

2006 Pearson Education, Inc. All rights reserved.

24.5 mutable Class Members

• Storage class specifier mutable– Specifies that a data member can always be modified

• Even in a const member function or const object

– Reduces the need to cast away “const-ness”

27

2006 Pearson Education, Inc. All rights reserved.

Portability Tip 24.1

The effect of attempting to modify an object that was defined as constant, regardless of whether that modification was made possible by a const_cast or C-style cast, varies among compilers.

28

2006 Pearson Education, Inc. All rights reserved.

Software Engineering Observation 24.3

mutable members are useful in classes that have “secret” implementation details that do not contribute to the logical value of an object.

29

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.5: fig24_05.cpp

2 // Demonstrating storage-class specifier mutable.

3 #include <iostream>

4 using std::cout;

5 using std::endl;

6

7 // class TestMutable definition

8 class TestMutable

9 {

10 public:

11 TestMutable( int v = 0 )

12 {

13 value = v;

14 } // end TestMutable constructor

15

16 int getValue() const

17 {

18 return value++; // increments value

19 } // end function getValue

20 private:

21 mutable int value; // mutable member

22 }; // end class TestMutable

Outline

fig24_05.cpp

(1 of 2)

value can be modified inside a const member function because it is a mutable data member

Declare data member value as mutable

30

2006 Pearson Education, Inc. All rights reserved.

23

24 int main()

25 {

26 const TestMutable test( 99 );

27

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

29 cout << "\nModified value: " << test.getValue() << endl;

30 return 0;

31 } // end main

Initial value: 99

Modified value: 100

Outline

fig24_05.cpp

(2 of 2)

31

2006 Pearson Education, Inc. All rights reserved.

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

•.* and ->* operators– Used for accessing class members via pointers

• Client code can create pointers only to class members that are accessible to that client code

– Rarely used• Used primarily by advanced C++ programmers

32

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.6: fig24_06.cpp

2 // Demonstrating operators .* and ->*.

3 #include <iostream>

4 using std::cout;

5 using std::endl;

6

7 // class Test definition

8 class Test

9 {

10 public:

11 void test()

12 {

13 cout << "In test function\n";

14 } // end function test

15

16 int value; // public data member

17 }; // end class Test

18

19 void arrowStar( Test * ); // prototype

20 void dotStar( Test * ); // prototype

21

22 int main()

23 {

24 Test test;

25 test.value = 8; // assign value 8

26 arrowStar( &test ); // pass address to arrowStar

27 dotStar( &test ); // pass address to dotStar

28 return 0;

29 } // end main

Outline

fig24_06.cpp

(1 of 2)

Call functions arrowStar and dotStar with the address of object test

33

2006 Pearson Education, Inc. All rights reserved.

30

31 // access member function of Test object using ->*

32 void arrowStar( Test *testPtr )

33 {

34 void ( Test::*memPtr )() = &Test::test; // declare function pointer

35 ( testPtr->*memPtr )(); // invoke function indirectly

36 } // end arrowStar

37

38 // access members of Test object data member using .*

39 void dotStar( Test *testPtr2 )

40 {

41 int Test::*vPtr = &Test::value; // declare pointer

42 cout << ( *testPtr2 ).*vPtr << endl; // access value

43 } // end dotStar In test function 8

Outline

fig24_06.cpp

(2 of 2)

Declare memPtr as a pointer to a member function of Test that takes no parameters and returns void

Initialize memPtr with the address of class Test’s member function named test

Invoke the member function stored in memPtr (i.e., test) using the ->* operatorDeclare vPtr as a pointer to an int

data member of class TestInitialize vPtr to the address

of the data member value

Dereference testPtr2 and use the .* operator to access the member to which vPtr points

34

2006 Pearson Education, Inc. All rights reserved.

Common Programming Error 24.2

Declaring a member-function pointer without enclosing the pointer name in parentheses is a syntax error.

35

2006 Pearson Education, Inc. All rights reserved.

Common Programming Error 24.3

Declaring a member-function pointer without preceding the pointer name with a class name followed by the scope resolution operator (::) is a syntax error.

36

2006 Pearson Education, Inc. All rights reserved.

Common Programming Error 24.4

Attempting to use the -> or * operator with a pointer to a class member generates syntax errors.

37

2006 Pearson Education, Inc. All rights reserved.

24.7 Multiple Inheritance

• Multiple Inheritance– When a derived class inherits members from two or more

base classes• Provide comma-separated list of base classes after the colon

following the derived class name

– Can cause ambiguity problems• Should be used only by experienced programmers

• Newer languages do not allow multiple inheritance

• A common problem occurs if more than one base class contains a member with the same name

– Solved by using the binary scope resolution operator

38

2006 Pearson Education, Inc. All rights reserved.

Good Programming Practice 24.2

Multiple inheritance is a powerful capability when used properly. Multiple inheritance should be used when an “is a” relationship exists between a new type and two or more existing types (i.e., type A “is a” type B and type A “is a” type C).

39

2006 Pearson Education, Inc. All rights reserved.

Software Engineering Observation 24.4

Multiple inheritance can introduce complexity into a system. Great care is required in the design of a system to use multiple inheritance properly; it should not be used when single inheritance and/or composition will do the job.

40

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.7: Base1.h

2 // Definition of class Base1

3 #ifndef BASE1_H

4 #define BASE1_H

5

6 // class Base1 definition

7 class Base1

8 {

9 public:

10 Base1( int parameterValue )

11 {

12 value = parameterValue;

13 } // end Base1 constructor

14

15 int getData() const

16 {

17 return value;

18 } // end function getData

19 protected: // accessible to derived classes

20 int value; // inherited by derived class

21 }; // end class Base1

22

23 #endif // BASE1_H

Outline

Base1.h

(1 of 1)

Class Base1 declares member function getData

41

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.8: Base2.h

2 // Definition of class Base2

3 #ifndef BASE2_H

4 #define BASE2_H

5

6 // class Base2 definition

7 class Base2

8 {

9 public:

10 Base2( char characterData )

11 {

12 letter = characterData;

13 } // end Base2 constructor

14

15 char getData() const

16 {

17 return letter;

18 } // end function getData

19 protected: // accessible to derived classes

20 char letter; // inherited by derived class

21 }; // end class Base2

22

23 #endif // BASE2_H

Outline

Base2.h

(1 of 1)

Class Base2 also declares member function getData

42

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.9: 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 using std::ostream;

9

10 #include "Base1.h"

11 #include "Base2.h"

12

13 // class Derived definition

14 class Derived : public Base1, public Base2

15 {

16 friend ostream &operator<<( ostream &, const Derived & );

17 public:

18 Derived( int, char, double );

19 double getReal() const;

20 private:

21 double real; // derived class's private data

22 }; // end class Derived

23

24 #endif // DERIVED_H

Outline

Derived.h

(1 of 1)

Class Derived inherits from both class Base1 and class Base2 through multiple inheritance

43

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.10: 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

13 {

14 return real;

15 } // end function getReal

16

17 // display all data members of Derived

18 ostream &operator<<( ostream &output, const Derived &derived )

19 {

20 output << " Integer: " << derived.value << "\n Character: "

21 << derived.letter << "\nReal number: " << derived.real;

22 return output; // enables cascaded calls

23 } // end operator<<

Outline

Derived.cpp

(1 of 1)

Base-class constructors are called in the order that the inheritance is specified

44

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.11: fig24_11.cpp

2 // Driver for multiple inheritance example.

3 #include <iostream>

4 using std::cout;

5 using std::endl;

6

7 #include "Base1.h"

8 #include "Base2.h"

9 #include "Derived.h"

10

11 int main()

12 {

13 Base1 base1( 10 ), *base1Ptr = 0; // create Base1 object

14 Base2 base2( 'Z' ), *base2Ptr = 0; // create Base2 object

15 Derived derived( 7, 'A', 3.5 ); // create Derived object

16

17 // print data members of base-class objects

18 cout << "Object base1 contains integer " << base1.getData()

19 << "\nObject base2 contains character " << base2.getData()

20 << "\nObject derived contains:\n" << derived << "\n\n";

21

22 // print data members of derived-class object

23 // scope resolution operator resolves getData ambiguity

24 cout << "Data members of Derived can be accessed individually:"

25 << "\n Integer: " << derived.Base1::getData()

26 << "\n Character: " << derived.Base2::getData()

27 << "\nReal number: " << derived.getReal() << "\n\n";

28 cout << "Derived can be treated as an object of either base class:\n";

29

Outline

fig24_11.cpp

(1 of 2)

Get the value of the variable inherited from class Base1

Get the value of the variable inherited from class Base2

45

2006 Pearson Education, Inc. All rights reserved.

30 // treat Derived as a Base1 object

31 base1Ptr = &derived;

32 cout << "base1Ptr->getData() yields " << base1Ptr->getData() << '\n';

33

34 // treat Derived as a Base2 object

35 base2Ptr = &derived;

36 cout << "base2Ptr->getData() yields " << base2Ptr->getData() << endl;

37 return 0;

38 } // end main 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

Outline

fig24_11.cpp

(2 of 2)

base1Ptr calls Base1’s getData member function

base2Ptr calls Base2’s getData member function

46

2006 Pearson Education, Inc. All rights reserved.

24.8 Multiple Inheritance and virtual Base Classes

• Base-class subobject– The members of a base class that are inherited into a

derived class

• Diamond inheritance– When two classes inherit from the same base class, and

another derived class inherits from both of those two classes, forming a diamond-like structure

– Example• basic_istream and basic_ostream each inherit from basic_ios

• basic_iostream inherits from both basic_istream and basic_ostream

47

2006 Pearson Education, Inc. All rights reserved.

Fig. 24.12 | Multiple inheritance to form class basic_iostream.

48

2006 Pearson Education, Inc. All rights reserved.

24.8 Multiple Inheritance and virtual Base Classes (Cont.)

• Diamond inheritance (Cont.)– Ambiguity problem (from example)

• Class basic_iostream could contain two copies of the basic_ios subobject

– One inherited via basic_istream and one inherited via basic_ostream

– Compiler would not know which version to use

49

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.13: fig24_13.cpp

2 // Attempting to polymorphically call a function that is

3 // multiply inherited from two base classes.

4 #include <iostream>

5 using std::cout;

6 using std::endl;

7

8 // class Base definition

9 class Base

10 {

11 public:

12 virtual void print() const = 0; // pure virtual

13 }; // end class Base

14

15 // class DerivedOne definition

16 class DerivedOne : public Base

17 {

18 public:

19 // override print function

20 void print() const

21 {

22 cout << "DerivedOne\n";

23 } // end function print

24 }; // end class DerivedOne

Outline

fig24_13.cpp

(1 of 3) Base class Base contains pure virtual function print

Class DerivedOne inherits from class Base and overrides the print function

50

2006 Pearson Education, Inc. All rights reserved.

25

26 // class DerivedTwo definition

27 class DerivedTwo : public Base

28 {

29 public:

30 // override print function

31 void print() const

32 {

33 cout << "DerivedTwo\n";

34 } // end function print

35 }; // end class DerivedTwo

36

37 // class Multiple definition

38 class Multiple : public DerivedOne, public DerivedTwo

39 {

40 public:

41 // qualify which version of function print

42 void print() const

43 {

44 DerivedTwo::print();

45 } // end function print

46 }; // end class Multiple

47

48 int main()

49 {

50 Multiple both; // instantiate Multiple object

51 DerivedOne one; // instantiate DerivedOne object

52 DerivedTwo two; // instantiate DerivedTwo object

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

Outline

fig24_13.cpp

(2 of 3)

Class DerivedTwo inherits from class Base and overrides the print function

Class Multiple inherits from both classes DerivedOne and DerivedTwo

Multiple overrides function print to call DerivedTwo’s version of print

51

2006 Pearson Education, Inc. All rights reserved.

54

55 array[ 0 ] = &both; // ERROR--ambiguous

56 array[ 1 ] = &one;

57 array[ 2 ] = &two;

58

59 // polymorphically invoke print

60 for ( int i = 0; i < 3; i++ )

61 array[ i ] -> print();

62

63 return 0;

64 } // end main

C:\Projects\cpphtp5\examples\ch24\Fig24_20\Fig24_20.cpp(55): error C2594: '=' : ambiguous conversions from 'Multiple *' to 'Base *'

Outline

fig24_13.cpp

(3 of 3)

The compiler does not know which subobject in both the pointer array[ 0 ] should point to

52

2006 Pearson Education, Inc. All rights reserved.

24.8 Multiple Inheritance and virtual Base Classes (Cont.)

•virtual inheritance– A base class can be inherited as virtual

• Only one subobject will appear in the derived class

• Called virtual base-class inheritance

• If the virtual base class’s constructor requires arguments

– The most derived class must explicitly invoke that constructor

53

2006 Pearson Education, Inc. All rights reserved.

1 // Fig. 24.14: fig24_14.cpp

2 // Using virtual base classes.

3 #include <iostream>

4 using std::cout;

5 using std::endl;

6

7 // class Base definition

8 class Base

9 {

10 public:

11 virtual void print() const = 0; // pure virtual

12 }; // end class Base

13

14 // class DerivedOne definition

15 class DerivedOne : virtual public Base

16 {

17 public:

18 // override print function

19 void print() const

20 {

21 cout << "DerivedOne\n";

22 } // end function print

23 }; // end DerivedOne class

Outline

fig24_14.cpp

(1 of 3)

Class DerivedOne uses virtual inheritance to inherit from class Base

54

2006 Pearson Education, Inc. All rights reserved.

24

25 // class DerivedTwo definition

26 class DerivedTwo : virtual public Base

27 {

28 public:

29 // override print function

30 void print() const

31 {

32 cout << "DerivedTwo\n";

33 } // end function print

34 }; // end DerivedTwo class

35

36 // class Multiple definition

37 class Multiple : public DerivedOne, public DerivedTwo

38 {

39 public:

40 // qualify which version of function print

41 void print() const

42 {

43 DerivedTwo::print();

44 } // end function print

45 }; // end Multiple class

Outline

fig24_14.cpp

(2 of 3)

Class DerivedTwo uses virtual inheritance to inherit from class Base

Only one subobject of type Base is inherited into class Multiple

55

2006 Pearson Education, Inc. All rights reserved.

46

47 int main()

48 {

49 Multiple both; // instantiate Multiple object

50 DerivedOne one; // instantiate DerivedOne object

51 DerivedTwo two; // instantiate DerivedTwo object

52

53 // declare array of base-class pointers and initialize

54 // each element to a derived-class type

55 Base *array[ 3 ];

56 array[ 0 ] = &both;

57 array[ 1 ] = &one;

58 array[ 2 ] = &two;

59

60 // polymorphically invoke function print

61 for ( int i = 0; i < 3; i++ )

62 array[ i ]->print();

63

64 return 0;

65 } // end main

DerivedTwo

DerivedOne

DerivedTwo

Outline

fig24_14.cpp

(3 of 3)

The compiler now allows the implicit conversion of &both to array[ 0 ]

56

2006 Pearson Education, Inc. All rights reserved.

Software Engineering Observation 24.5

Providing a default constructor for virtual base classes simplifies hierarchy design.

57

2006 Pearson Education, Inc. All rights reserved.

24.8 Multiple Inheritance and virtual Base Classes (Cont.)

• Additional information on multiple inheritance– cplus.about.com/library/weekly/aa121302a .htm

• Tutorial on multiple inheritance with detailed example

– cpptips.hyperformix.com/MultipleInher.html• Provides technical tips that explain several multiple

inheritance issues

– www.parashift.com/c++-faq-lite/multiple-inheritance.html

• Detailed technical explanation of multiple inheritance and virtual inheritance