1 / 42

Chapter 21 - Standard C++ Language Additions

Chapter 21 - Standard C++ Language Additions. Outline 21.1 Introduction 21.2 bool Data Type 21.3 static_cast Operator 21.4 const_cast Operator 21.5 reinterpret_cast Operator 21.6 namespaces 21.7 Run-Time Type Information (RTTI) 21.8 Operator Keywords

varian
Télécharger la présentation

Chapter 21 - Standard C++ Language Additions

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

E N D

Presentation Transcript


  1. Chapter 21 - Standard C++ Language Additions Outline 21.1 Introduction 21.2 bool Data Type 21.3 static_cast Operator 21.4 const_cast Operator 21.5 reinterpret_cast Operator 21.6 namespaces 21.7 Run-Time Type Information (RTTI) 21.8 Operator Keywords 21.9 explicit Constructors 21.10 mutable Class Members 21.11 Pointers to Class Members (.* and ->*) 21.12 Multiple Inheritance and virtual Base Classes

  2. 21.1 Introduction • We shall cover standard C++ features • data type bool • cast operators • namespaces • run-time type information (RTTI) • operator keywords

  3. 21.2 bool Data Type • bool - can be false or true • preferable to 0 (false) and non-zero (true) • outputting bool variables • numerical default (0 or 1) • stream manipulator boolalpha • outputs string "true" or "false" Examples: cout << boolVariable cout << boolalpha << boolVariable

  4. 1 // Fig. 21.1: fig21_01.cpp 2 // Demonstrating data type bool. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 using std::cin; 8 using std::boolalpha; 9 10 int main() 11 { 12 bool boolean = false; 13 int x = 0; 14 15 cout << "boolean is " << boolean 16 << "\nEnter an integer: "; 17 cin >> x; 18 19 cout << "integer " << x << " is" 20 << ( x ? " nonzero " : " zero " ) 21 << "and interpreted as "; 22 1. Initialize bool variable an int. 2. Input a variable. 3. Print the bool value of the int. 3.1 Print the value of bool variable. boolean is 0 Enter an integer: 22

  5. 23 if ( x ) 24 cout << "true\n"; Notice how the output varies. 25 else 26 cout << "false\n"; 27 28 boolean = true; 29 cout << "boolean is " << boolean; 30 cout << "\nboolean output with boolalpha manipulator is " 31 << boolalpha << boolean << endl; 32 33 return 0; 34 } integer 22 is nonzero and interpreted as true 3.2 Print the string value of the bool variable. Program Output boolean is 1 boolean output with boolalpha manipulator is true boolean is 0 Enter an integer: 22 integer 22 is nonzero and interpreted as true boolean is 1 boolean output with boolalpha manipulator is true

  6. 21.3 static_cast Operator • C++ has 4 separate, specific casts • static_cast - conversion between types • type checking at compile time • standard conversions: void* to char*, int to float, etc. • base class pointers to derived class pointers • Format: static_cast<type to convert to>(object to convert) int z = 3; float x = static_cast<int>(z);

  7. 1 // Fig. 21.2: fig21_02.cpp 2 // Demonstrating the static_cast operator. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 class BaseClass { convert double to int 9 public: 10 void f( void ) const { cout << "BASE\n"; } 11 }; 12 13 class DerivedClass : public BaseClass { 14 public: 15 void f( void ) const { cout << "DERIVED\n"; } 16 }; 17 18 void test( BaseClass * ); 19 20 int main() 21 { 22 // use static_cast for a conversion 23 double d = 8.22; 24 int x = static_cast< int >( d ); 25 26 cout << "d is " << d << "\nx is " << x << endl; 27 28 BaseClass * basePtr = new DerivedClass; 29 test( basePtr ); // call test 30 delete basePtr; 1. Define class BaseClass 1.1 Define member function 1.2 Define class DerivedClass 1.3 Define member function 1.4 Global function prototype (calls function f) 2. Function calls 3. Output results d is 8.22 x is 8

  8. 31 32 return 0; 33 } 34 35 void test( BaseClass * basePtr ) 36 { 37 DerivedClass *derivedPtr; 38 converts a base pointer to a derived pointer, and calls the derived function f 39 // cast base class pointer into derived class pointer 40 derivedPtr = static_cast< DerivedClass * >( basePtr ); 41 derivedPtr->f(); // invoke DerivedClass function f 42 } 3.1 Function definition Program Output d is 8.22 x is 8 DERIVED

  9. 1 // Fig. 21.2: fig21_02.cpp 2 // Demonstrating the static_cast operator. In constfunction print the this pointer is originally const ConstCastTest *.It is cast into type ConstCastTest *, and can then be modified. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 class BaseClass { 9 public: 10 void f( void ) const { cout << "BASE\n"; } 11 }; 12 13 class DerivedClass : public BaseClass { 14 public: 15 void f( void ) const { cout << "DERIVED\n"; } 16 }; 17 18 void test( BaseClass * ); 19 20 int main() 21 { 22 // use static_cast for a conversion 23 double d = 8.22; 24 int x = static_cast< int >( d ); 25 26 cout << "d is " << d << "\nx is " << x << endl; 27 28 BaseClass * basePtr = new DerivedClass; 29 test( basePtr ); // call test 30 delete basePtr; 1. Class definition 1.1 Initialize objects 2. Print

  10. 31 32 return 0; 33 } 34 35 void test( BaseClass * basePtr ) 36 { 37 DerivedClass *derivedPtr; 38 39 // cast base class pointer into derived class pointer 40 derivedPtr = static_cast< DerivedClass * >( basePtr ); 41 derivedPtr->f(); // invoke DerivedClass function f 42 } 3. Function definition Program Output d is 8.22 x is 8 DERIVED

  11. 21.4 const_cast Operator • const_cast - cast away const or volatile • cannot be used directly to cast away const-ness • use pointers

  12. 1 // Fig. 21.3: fig21_03.cpp 2 // Demonstrating the const_cast operator. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 class ConstCastTest { 9 public: 10 void setNumber( int ); 11 int getNumber() const; 12 void printNumber() const; 13 private: 14 int number; 15 }; 16 17 void ConstCastTest::setNumber( int num ) { number = num; } 18 19 int ConstCastTest::getNumber() const { return number; } 20 21 void ConstCastTest::printNumber() const 22 { 23 cout << "\nNumber after modification: "; 24 25 // the expression number-- would generate compile error 1. Define class ConstCastTest 1.1 Define member functions

  13. 26 // undo const-ness to allow modification 27 const_cast< ConstCastTest * >( this )->number--; Casts the this pointer into type ConstCastTest *. This casts away the "const-ness" and allows number to be modified. 28 29 cout << number << endl; 30 } 31 32 int main() 33 { 34 ConstCastTest x; 35 x.setNumber( 8 ); // set private data number to 8 36 37 cout << "Initial value of number: " << x.getNumber(); 38 39 x.printNumber(); 40 return 0; 41 } 2. Create and initialize object 3. Modify and print object with a const function. Program Output Initial value of number: 8 Number after modification: 7

  14. 21.5 reinterpret_cast Operator • reinterpret_cast - for nonstandard casts • one pointer type to another pointer type, void* to int, etc. • cannot be used for standard casts (int to double, etc.).

  15. 1 // Fig. 21.4: fig21_04.cpp 2 // Demonstrating the reinterpret_cast operator. 3 #include <iostream> 4 ptr (type int *) cast to a pointer of type (char *). 5 using std::cout; 6 using std::endl; 7 8 int main() 9 { 10 int x = 120, *ptr = &x; 120 is the ASCII character code for 'x' 11 12 cout << *reinterpret_cast<char *>( ptr ) << endl; 13 14 return 0; 15 } 1. Initialize variables and pointers 2. Cast a pointer to pointer of a different type 3. Output data Program Output x

  16. 21.6 namespaces • variables with same name and different scopes can overlap • need to distinguish them • a namespace defines a scope for local and global identifiers. • body delimited by braces {} • use (::) to access namespace members: namespace_name::member • or, a using statement must occur before name is used using namespace namespace_name; -members of thenamespace do not need a prefix • not guaranteed to be unique • can be nested

  17. 21.6 namespaces (II) • Unnamed namespaces • occupy global namespace • directly accessible • do not need namespace name • global variables are in global namespace • accessible in all scopes

  18. 1 // Fig. 21.5: fig21_05.cpp 2 // Demonstrating namespaces. 3 #include <iostream> 4 usingnamespace std; // use std namespace 5 6 int myInt = 98; // global variable 7 8 namespace Example { Unnamed namespace members do not need qualifiers 9 constdouble PI = 3.14159; 10 constdouble E = 2.71828; 11 int myInt = 8; 12 void printValues(); 13 14 namespace Inner { // nested namespace 15 enum Years { FISCAL1 = 1990, FISCAL2, FISCAL3 }; 16 } 17 } 18 19 namespace { // unnamed namespace 20 double d = 88.22; 21 } 22 23 int main() 24 { 25 // output value d of unnamed namespace 26 cout << "d = " << d; 27 28 // output global variable 29 cout << "\n(global) myInt = " << myInt; 1. Use std namespace 1.1 Declare global variable 1.2 Define namespace Example 1.3 Define namespace inner 1.4 Define unnamed namespace 2. Print variables d = 88.22 (global) myInt = 98

  19. 31 // output values of Example namespace 32 cout << "\nPI = " << Example::PI << "\nE = " 33 << Example::E << "\nmyInt = " 34 << Example::myInt << "\nFISCAL3 = " 35 << Example::Inner::FISCAL3 << endl; 36 37 Example::printValues(); // invoke printValues function 38 39 return 0; Function printValues is a member of Example and does not need a namespace qualifier. 40 } 41 42 void Example::printValues() 43 { 44 cout << "\nIn printValues:\n" << "myInt = " 45 << myInt << "\nPI = " << PI << "\nE = " 46 << E << "\nd = " << d << "\n(global) myInt = " 47 << ::myInt << "\nFISCAL3 = " 48 << Inner::FISCAL3 << endl; 49 } 2. Print variables 3. Function definition PI = 3.14159 E = 2.71828 myInt = 8 FISCAL3 = 1992 In printValues: myInt = 8 PI = 3.14159 E = 2.71828 d = 88.22 (global) myInt = 98 FISCAL3 = 1992

  20. d = 88.22 (global) myInt = 98 PI = 3.14159 E = 2.71828 myInt = 8 FISCAL3 = 1992 In printValues: myInt = 8 PI = 3.14159 E = 2.71828 d = 88.22 (global) myInt = 98 FISCAL3 = 1992 Program Output

  21. 21.7 Run-Time Type Information (RTTI) • determines an object's type at run time • typeid (in <typeinfo>) typeid(object).name() - returns the name of the object as a C-style string • dynamic_cast - for polymorphic programming • often used to downcast base-class pointer to derived-class pointer • used with virtual functions

  22. 1 // Fig. 21.7: fig21_07.cpp 2 // Demonstrating dynamic_cast. 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 const double PI = 3.14159; 9 10 class Shape { 11 public: 12 virtualdouble area() const { return 0.0; } 13 }; 14 15 class Circle : public Shape { 16 public: 17 Circle( int r = 1 ) { radius = r; } 18 19 virtualdouble area() const 20 { 21 return PI * radius * radius; 22 }; 23 protected: 24 int radius; 25 }; 26 27 class Cylinder : public Circle { 28 public: 29 Cylinder( int h = 1 ) { height = h; } 30 31 virtualdouble area() const 32 { 33 return 2 * PI * radius * height + 1. Define base and derived classes

  23. 34 2 * Circle::area(); 35 } 36 private: Notice how shapePtris cast to various types. If it is not of the right type, the cast returns 0. 37 int height; 38 }; 39 40 void outputShapeArea( const Shape * ); // prototype 41 42 int main() 43 { 44 Circle circle; 45 Cylinder cylinder; 46 Shape *ptr = 0; 47 48 outputShapeArea( &circle ); // output circle's area 49 outputShapeArea( &cylinder ); // output cylinder's area 50 outputShapeArea( ptr ); // attempt to output area 51 return 0; 52 } 53 54 void outputShapeArea( const Shape *shapePtr ) 55 { 56 const Circle *circlePtr; 57 const Cylinder *cylinderPtr; 58 59 // cast Shape * to a Cylinder * 60 cylinderPtr = dynamic_cast< const Cylinder * >( shapePtr ); 61 62 if ( cylinderPtr != 0 ) // if true, invoke area() 63 cout << "Cylinder's area: " << shapePtr->area(); 64 else { // shapePtr does not refer to a cylinder 65 66 // cast shapePtr to a Circle * 1.1 Function prototype 1.2 Declare objects 2. Function calls 3. Define function.

  24. 67 circlePtr = dynamic_cast< const Circle * >( shapePtr ); 68 69 if ( circlePtr != 0 ) // if true, invoke area() 70 cout << "Circle's area: " << circlePtr->area(); 71 else 72 cout << "Neither a Circle nor a Cylinder."; 73 } 74 Notice how shapePtris cast to various types. If it is not of the right type, the cast returns 0. 75 cout << endl; 76 } 3. Define function. Program Output Circle's area: 3.14159 Cylinder's area: 12.5664 Neither a Circle nor a Cylinder.

  25. 21.8 Operator Keywords • can use keywords in place of operators (such as !, &, ^, etc.). • use header <iso646.h> (may vary with compiler)

  26. 1 // Fig. 21.9: fig21_09.cpp 2 // Demonstrating operator keywords. 3 #include <iostream> Operator keywords can be used instead of the symbols 4 5 using std::cout; 6 using std::endl; 7 using std::boolalpha; 8 9 #include <iso646.h> 10 11 int main() 12 { 13 int a = 8, b = 22; 14 15 cout << boolalpha 16 << " a and b: " << ( a and b ) 17 << "\n a or b: " << ( a or b ) 18 << "\n not a: " << ( not a ) 19 << "\na not_eq b: " << ( a not_eq b ) 20 << "\na bitand b: " << ( a bitand b ) 21 << "\na bit_or b: " << ( a bitor b ) 22 << "\n a xor b: " << ( a xor b ) 23 << "\n compl a: " << ( compl a ) 24 << "\na and_eq b: " << ( a and_eq b ) 25 << "\n a or_eq b: " << ( a or_eq b ) 26 << "\na xor_eq b: " << ( a xor_eq b ) << endl; 27 28 return 0; 29 } 1. Load header 1.1 Initialize variables 2. Use operator keywords 3. Print results

  27. a and b: true a or b: true not a: false a not_eq b: false a bitand b: 22 a bit_or b: 22 a xor b: 0 compl a: -23 a and_eq b: 22 a or_eq b: 30 a xor_eq b: 30 Program Output

  28. 21.9 explicit Constructors • constructors with one argument can be used for implicit conversion • type received by constructor turned into an object • automatic conversion sometimes undesirable • keyword explicitprevents implicit conversion • use before constructor prototype in class definition

  29. 1 // Fig. 21.9: fig21_09.cpp 2 // Demonstrating operator keywords. 15is not anArrayobject, but it is implicitly converted to anArray object using the conversion constructor. This new object is printed using outputArray. 3 #include <iostream> 4 If the keyword explicitcomes before the constructor, this program will issue a compiler error - outputArraycannot take an int. 5 using std::cout; 6 using std::endl; 7 using std::boolalpha; 8 9 #include <iso646.h> 10 11 int main() 12 { 13 int a = 8, b = 22; 14 15 cout << boolalpha 16 << " a and b: " << ( a and b ) 17 << "\n a or b: " << ( a or b ) 18 << "\n not a: " << ( not a ) 19 << "\na not_eq b: " << ( a not_eq b ) 20 << "\na bitand b: " << ( a bitand b ) 21 << "\na bit_or b: " << ( a bitor b ) 22 << "\n a xor b: " << ( a xor b ) 23 << "\n compl a: " << ( compl a ) 24 << "\na and_eq b: " << ( a and_eq b ) 25 << "\n a or_eq b: " << ( a or_eq b ) 26 << "\na xor_eq b: " << ( a xor_eq b ) << endl; 27 28 return 0; 29 } 1. Define Array class 1.1 Define constructor 1.2 Define destructor 2. Create object 2.1 Print Array object 2.2 Print int 3. Function definition

  30. a and b: true a or b: true not a: false a not_eq b: false a bitand b: 22 a bit_or b: 22 a xor b: 0 compl a: -23 a and_eq b: 22 a or_eq b: 30 a xor_eq b: 30 Program Output

  31. 1 // Fig 21.10: array2.h 21 // Fig 21.10: array2.cpp 2 // Simple class Array (for integers) 22 // Member function definitions for class Array 23 #include <iostream> 3 #ifndef ARRAY2_H 4 #define ARRAY2_H 24 5 25 using std::cout; 6 #include <iostream> 26 using std::ostream; 27 7 8 using std::ostream; 28 #include <cassert> 29 #include "array2.h" 9 30 10 class Array { 11 friend ostream &operator<<( ostream &, const Array & ); 12 public: 13 Array( int = 10 ); // default/conversion constructor 14 ~Array(); // destructor 15 private: 16 int size; // size of the array 17 int *ptr; // pointer to first element of array 18 }; 19 20 #endif 1. Class definition 1.1 Function prototype 1.2 Member variables ---------------------- 1. Load header file

  32. 31 // Default constructor for class Array (default size 10) 32 Array::Array( int arraySize ) 33 { 34 size = ( arraySize > 0 ? arraySize : 10 ); 35 cout << "Array constructor called for " 36 << size << " elements\n"; 37 38 ptr = newint[ size ]; // create space for array 39 assert( ptr != 0 ); // terminate if memory not allocated 40 41 for ( int i = 0; i < size; i++ ) 42 ptr[ i ] = 0; // initialize array 43 } 44 45 // Destructor for class Array 46 Array::~Array() { delete [] ptr; } 47 48 // Overloaded output operator for class Array 49 ostream &operator<<( ostream &output, const Array &a ) 50 { 51 int i; 52 53 for ( i = 0; i < a.size; i++ ) 54 output << a.ptr[ i ] << ' ' ; 55 56 return output; // enables cout << x << y; 57 } 1.1 Function definitions

  33. 58 // Fig 21.10: fig21_10.cpp 59 // Driver for simple class Array 60 #include <iostream> 61 62 using std::cout; 63 outputArray needs a parameter of type const Array &, so 15 is converted into an Array by the conversion constructor. 64 #include "array2.h" 65 66 void outputArray( const Array & ); 67 68 int main() 69 { 70 Array integers1( 7 ); 71 72 outputArray( integers1 ); // output Array integers1 73 74 outputArray( 15 ); // convert 15 to an Array and output 75 76 return 0; 77 } 78 79 void outputArray( const Array &arrayToOutput ) 80 { 81 cout << "The array received contains:\n" 82 << arrayToOutput << "\n\n"; 83 } 1. Load header 1.1 Initialize object 2. Print object 3. Function definition

  34. 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 Program Output

  35. 21.10 mutable Class Members • mutable data member • always modifiable, even in a const function or object • permanently allows a const data member to be modified • const_cast: • used every time a const data member must be modified • reduces risk of accidentally modifying a const variable

  36. 21.11 Pointers to Class Members (.* and ->*) • pointers to class members are different from normal pointers • use .* and ->* instead of . and -> when accessing class members (functions and data)

  37. 1 // Fig. 21.13 fig21_13.cpp 2 // Demonstrating operators .* and ->* 3 #include <iostream> 4 5 using std::cout; 6 using std::endl; 7 8 class Test { 9 public: 10 void function() { cout << "function\n"; } 11 int value; 12 }; 13 14 void arrowStar( Test * ); 15 void dotStar( Test * ); 16 17 int main() 18 { 19 Test t; 20 21 t.value = 8; 22 arrowStar( &t ); 23 dotStar( &t ); 24 return 0; 25 } 1. Class definition 1.1 Function prototypes 1.2 Initialize object 2. Function calls

  38. 26 27 void arrowStar( Test *tPtr ) 28 { arrowStardeclares and initializes memPtr to point to a function in Test that takes no parameters and returns no value. &Test::function to get the offset into the class for member function function. Without Test::, memPtr is a standard pointer. 29 void ( Test::*memPtr )() = &Test::function; 30 ( tPtr->*memPtr )(); // invoke function indirectly 31 } dotStardeclares and initializes vPtr to point to value. The .* operator is then used to access the member to which vPtr points. 32 33 void dotStar( Test *tPtr ) 34 { 35 int Test::*vPtr = &Test::value; 36 cout << ( *tPtr ).*vPtr << endl; // access value 37 } 3. Function definitions Program Output function 8

  39. 21.12 Multiple Inheritance and virtual Base Classes • Ambiguities can result with multiple inheritance • iostream could have duplicate subobjects (data from ios inherited into ostream and istream). • Upcasting an iostream pointer to an ios object creates a problem. Two ios subobjects could exist: which one is used? • Ambiguous, results in syntax error (of course, iostream does not actually have this problem) ios ostream istream iostream

  40. Base Class virtual inheritance virtual inheritance First Derived Class Second Derived Class Multiply-Derived Class 21.12 Multiple Inheritance and virtual Base Classes (II) • Use virtual base class inheritance • only one subobject of the base is inherited into the multiply derived class.

  41. 1 // Fig. 21.15: fig21_15.cpp 2 // Attempting to polymorphically call a function 3 // multiply inherited from two base classes. 4 #include <iostream> 5 6 using std::cout; 7 using std::endl; 8 9 class Base { 10 public: 11 virtualvoid print() const = 0; // pure virtual 12 }; 13 14 class DerivedOne : public Base { 15 public: 16 // override print function 17 void print() const { cout << "DerivedOne\n"; } 18 }; 19 20 class DerivedTwo : public Base { 21 public: 22 // override print function 23 void print() const { cout << "DerivedTwo\n"; } 24 }; 25 26 class Multiple : public DerivedOne, public DerivedTwo { 27 public: 28 // qualify which version of function print 29 void print() const { DerivedTwo::print(); } 30 }; 31 1. Define base class 1.1 Define non-virtual derived classes 1.2 Define multiply derived class

  42. 32 int main() The address of both is implicitly converted to a base class pointer. This is ambiguous because class Multiple has duplicate subobjects inherited from Base. 33 { 34 Multiple both; // instantiate Multiple object 35 DerivedOne one; // instantiate DerivedOne object 36 DerivedTwo two; // instantiate DerivedTwo object If DerivedOneandDerivedTwo had used virtualinheritance, no errors would result and the objects will be printed. 37 38 Base *array[ 3 ]; 39 array[ 0 ] = &both; // ERROR--ambiguous 40 array[ 1 ] = &one; 41 array[ 2 ] = &two; 42 43 // polymorphically invoke print 44 for ( int k = 0; k < 3; k++ ) 45 array[ k ] -> print(); 46 47 return 0; 48 } 1.3 Create class objects 1.4 Create an array of base class pointers. 2. Initialize array elements Program Output Compiling... Fig21_15.cpp fig21_15.cpp(39) : error C2594: '=' : ambiguous conversions from 'class Multiple *' to 'class Base *'

More Related