You are on page 1of 55

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

Outline

// Fig. 22.1: fig22_01.cpp


// Demonstrating operator const_cast.
#include <iostream>

fig22_01.cpp
(1 of 2)

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

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--;

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

cout << number << endl;

fig22_01.cpp
output (1 of 1)

// end printNumber

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

Outline

// Fig. 22.2: fig22_02.cpp


// Demonstrating operator reinterpret_cast.
#include <iostream>

fig22_02.cpp
(1 of 1)

using std::cout;
using std::endl;
int main()
{
int x = 120;
int *ptr = &x;

fig22_02.cpp
output (1 of 1)

Create an int *. Cast it to a


char * for printing. 120 is
the ASCII value of 'x'.

// 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

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, different
variable
from the global integer1.

// prototypeNote

the nested namespace


Inner.

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

// end Inner

// end Example

2003 Prentice Hall, Inc.


All rights reserved.

1
0

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

// create unnamed namespace


namespace {
double doubleInUnnamed = 88.22;
}

// declare

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

// end unnamed namespace

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

// invoke printValues function

return 0;
}

// end main

2003 Prentice Hall, Inc.


All rights reserved.

1
1

54
55
56
57
58
59
60
61
62
63
64

Outline

// 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;
}

fig22_03.cpp
(3 of 3)

// end printValues

2003 Prentice Hall, Inc.


All rights reserved.

1
2

Outline

doubleInUnnamed = 88.22
(global) integer1 = 98
PI = 3.14159
E = 2.71828
integer1 = 8
FISCAL3 = 1992

fig22_03.cpp
output (1 of 1)

In printValues:
integer1 = 8
PI = 3.14159
E = 2.71828
doubleInUnnamed = 88.22
(global) integer1 = 98
FISCAL3 = 1992

2003 Prentice Hall, Inc.


All rights reserved.

1
3

22.5 Operator Keywords


Operator keywords

Can be used instead of operators


Useful for keyboards without ^ | & etc.

2003 Prentice Hall, Inc. All rights reserved.

14

22.5 Operator Keywords


Operator
Logical operator
keywords
&&
||
!
Inequality
operator keyword
!=
Bitwise operator
keywords
&
|
^
~
Bitwise
assignment
operator keywords
&=
|=

Operator keyword

Description

and
or
not

logical AND
logical OR
logical NOT

not_eq

Inequality

bitand
bitor
xor
compl

Bitwise
Bitwise
Bitwise
Bitwise

and_eq
or_eq

^=

xor_eq

Bitwise AND assignment


Bitwise inclusive OR
assignment
Bitwise exclusive OR
assignment

2003 Prentice Hall, Inc. All rights reserved.

AND
inclusive OR
exclusive OR
complement

15

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

Outline

// Fig. 22.5: fig22_05.cpp


// Demonstrating operator keywords.
#include <iostream>

fig22_05.cpp
(1 of 2)

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

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.

1
6

28
29
30
31

Outline

return 0;
}

// end main

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

fig22_05.cpp
(2 of 2)

fig22_05.cpp
output (1 of 1)

2003 Prentice Hall, Inc.


All rights reserved.

1
7

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.

18

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.

19

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

Outline

// Fig 22.6: array.h


// Simple class Array (for integers).
#ifndef ARRAY_H
#define ARRAY_H

array.h (1 of 1)

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

can

// end class Array

#endif

// ARRAY_H

2003 Prentice Hall, Inc.


All rights reserved.

2
0

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

Outline

// Fig 22.7: array.cpp


// Member function definitions for class Array.
#include <iostream>

array.cpp (1 of 2)

using std::cout;
using std::ostream;
#include <new>
#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.

2
1

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

Outline

// destructor for class Array


Array::~Array() { delete [] ptr; }

array.cpp (2 of 2)

// 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;
}

// enables cout << x << y;

// end operator<<

2003 Prentice Hall, Inc.


All rights reserved.

2
2

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

Outline

// Fig 22.8: fig22_08.cpp


// Driver for simple class Array.
#include <iostream>

fig22_08.cpp
(1 of 2)

using std::cout;
#include "array.h"
void outputArray( const Array & );
int main()
{
Array integers1( 7 );
outputArray( integers1 );
outputArray( 15 );
return 0;
}

//

// 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.

// end main

2003 Prentice Hall, Inc.


All rights reserved.

2
3

22
23
24
25
26
27
28
29

Outline

// print array contents


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

fig22_08.cpp
(2 of 2)
fig22_08.cpp
output (1 of 1)

// end outputArray

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.

2
4

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

Outline

// Fig. 22.9: array.h


// Simple class Array (for integers).
#ifndef ARRAY_H
#define ARRAY_H

array.h (1 of 1)

#include <iostream>
using std::ostream;
// 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

#endif

// ARRAY_H

2003 Prentice Hall, Inc.


All rights reserved.

2
5

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

Outline

// Fig. 22.10: array.cpp


// Member function definitions for class Array.
#include <iostream>

array.cpp (1 of 2)

using std::cout;
using std::ostream;
#include <new>
#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.

2
6

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

Outline

// destructor for class Array


Array::~Array() { delete [] ptr; }

array.cpp (2 of 2)

// 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;
}

// enables cout << x << y;

// end operator<<

2003 Prentice Hall, Inc.


All rights reserved.

2
7

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

Outline

// Fig. 22.11: fig22_11.cpp


// Driver for simple class Array.
#include <iostream>

fig22_11.cpp
(1 of 2)

using std::cout;
#include "array.h"
void outputArray( const Array & );
int main()
{
Array integers1( 7 );
outputArray( integers1 );

// output
Array
This
call integers1
will cause an

error

when compiled.

// ERROR: construction not allowed


outputArray( 15 ); // convert 15 to an Array and output
outputArray( Array( 15 ) ); // must use constructor
return 0;
}

// end main

2003 Prentice Hall, Inc.


All rights reserved.

2
8

26
27
28
29
30
31
32

Outline

// display array contents


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

fig22_11.cpp
(2 of 2)

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.

fig22_11.cpp
output (1 of 1)

test.exe - 1 error(s), 0 warning(s)

2003 Prentice Hall, Inc.


All rights reserved.

2
9

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.

30

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

Outline

// Fig. 21.12: fig21_12.cpp


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

Declare a mutable int. It


can be modified by const
functions.

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

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.

3
1

27
28
29
30

Outline

return 0;
}

// end main

Initial value: 99
Modified value: 100

fig21_12.cpp
(2 of 2)

fig21_12.cpp
output (1 of 1)

2003 Prentice Hall, Inc.


All rights reserved.

3
2

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.

33

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.

34

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

Outline

// Fig. 22.13 : fig22_13.cpp


// Demonstrating operators .* and ->*.
#include <iostream>

fig22_13.cpp
(1 of 2)

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

2003 Prentice Hall, Inc.


All rights reserved.

3
5

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

Outline

return 0;
}

// end main

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

Next, call function


directly.

// end arrowStar

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

// access value

// end dotStar

2003 Prentice Hall, Inc.


All rights reserved.

3
6

Outline

function
8

fig22_13.cpp
output (1 of 1)

2003 Prentice Hall, Inc.


All rights reserved.

3
7

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.

38

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

Outline

// Fig. 22.14: base1.h


// Definition of class Base1
#ifndef BASE1_H
#define BASE1_H

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

#endif

// BASE1_H

2003 Prentice Hall, Inc.


All rights reserved.

3
9

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

Outline

// Fig. 22.15: base2.h


// Definition of class Base2
#ifndef BASE2_H
#define BASE2_H

base2.h (1 of 1)

// 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

// end class Base2

#endif

// BASE2_H

2003 Prentice Hall, Inc.


All rights reserved.

4
0

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

Outline

// Fig. 22.16: derived.h


// Definition of class Derived which inherits
// multiple base classes (Base1 and Base2).
#ifndef DERIVED_H
#define DERIVED_H

derived.h (1 of 1)

#include <iostream>
using std::ostream;
#include "base1.h"
#include "base2.h"

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

#endif

// DERIVED_H

2003 Prentice Hall, Inc.


All rights reserved.

4
1

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"

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.

4
2

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

Outline

// Fig. 22.18: fig22_18.cpp


// Driver for multiple inheritance example.
#include <iostream>

fig22_18.cpp
(1 of 2)

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";

2003 Prentice Hall, Inc.


All rights reserved.

4
3

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

Outline

// 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;

fig22_18.cpp
(2 of 2)

Note calls to specific base


class functions.

Can treat derived-class pointer


as either base-class pointer.

return 0;
}

// end main

2003 Prentice Hall, Inc.


All rights reserved.

4
4

Outline

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:

fig22_18.cpp
output (1 of 1)

of Derived can be accessed individually:


7
A
3.5

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.

4
5

22.10 Multiple Inheritance and virtual Base


Classes
Ambiguities from multiple inheritance
ios
ostream

istream
iostream

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.

46

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

virtual
inheritance
First Derived Class

Second Derived Class

Multiply-Derived Class

2003 Prentice Hall, Inc. All rights reserved.

47

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

Outline

// 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;

This example will


demonstrate the ambiguity of
multiple inheritance.

// class Base definition


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

fig22_20.cpp
(1 of 3)

// pure virtual

// end class Base

// 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.

4
8

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

Outline

// class DerivedTwo definition


class DerivedTwo : public Base {
public:

fig22_20.cpp
(2 of 3)

// override print function


void print() const { cout << "DerivedTwo\n"; }
};

// end class DerivedTwo

// 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.

4
9

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;

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

// create array of base-class pointers


Which
Base *array[ 3 ];

fig22_20.cpp
(3 of 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.

5
0

Outline

c:\cpp4e\ch22\fig22_20_21\fig22_20.cpp(52) : error C2594: '=' :


ambiguous conversions from 'class Multiple *' to 'class Base *'
Error executing cl.exe.

fig22_20.cpp
output (1 of 1)

test.exe - 1 error(s), 0 warning(s)

2003 Prentice Hall, Inc.


All rights reserved.

5
1

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

Outline

// Fig. 22.21: fig22_21.cpp


// Using virtual base classes.
#include <iostream>

fig22_21.cpp
(1 of 3)

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

// 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.

5
2

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

Outline

// class DerivedTwo definition


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

Use virtual inheritance, as


before.

fig22_21.cpp
(2 of 3)

// 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.

5
3

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

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.

5
4

Outline

DerivedTwo
DerivedOne
DerivedTwo

fig22_21.cpp
output (1 of 1)

2003 Prentice Hall, Inc.


All rights reserved.

5
5