Date post: | 30-Dec-2015 |
Category: |
Documents |
Upload: | zaviera-nunez |
View: | 24 times |
Download: | 0 times |
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