abstract classes static and dynamic casting common ...natacha/teachfall_2010/csc330/... · the...

36
CSC 330 OO Software Design 1 POLYMORPHISM – 2 PART Abstract Classes Static and Dynamic Casting Common Programming Errors

Upload: others

Post on 19-Jul-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 1

POLYMORPHISM – 2 PART

Abstract ClassesStatic and Dynamic CastingCommon Programming Errors

Page 2: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 2

Abstract Base Classes

class B { // base classpublic:

virtual void m( ) { /* ... */ } // define m} ;class D1 : public B { // derived classpublic:

// … m could be--but need not be--overridden} ;class D2 : public B { // derived classpublic:

// … m could be--but need not be--overridden} ;

Page 3: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 3

DiscussionsDiscussions

We have a base class B and two derived classes, D1 and D2. The base class has a virtual method m that each derived class can override. Yet the derived classes D1 and D2 are not required to override method m. In object-oriented design, it is sometimes desirable to specify methods that classes such as D1 and D2 should define.

Page 4: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 4

Shared Interface

Definition: A collection of methods that different classes must define, with each class defining the methods in ways appropriate to it.C++ abstract base class can be used to specify methods that any derived class must define if the class is to have objects instantiate it. An abstract base class thus can be used to specify a shared interface.

Page 5: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 5

Abstract Base Classes and Pure Virtual Methods

An abstract base class is abstract in that no objects can instantiate it. Such a class can be used to specify virtualmethods that any derived class must override in, order to have objects instantiate the derived clas. A class must meet one requirement to be an abstract base class:The class must have a The class must have a pure virtualpure virtual method.method.A pure virtual method is one whose declaration A pure virtual method is one whose declaration ends with the special syntax ends with the special syntax =0=0.

Page 6: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 6

EXAMPLE 5.4. 1.

class ABC { // Abstract Base Classpublic:

virtual void open ( ) = 0;} ;

The class ABC has a pure virtual method named open.

By making open pure virtual, we thereby make ABC an abstract base class.

Page 7: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 7

EXAMPLE 5.4.2.class ABC { // Abstract Base Classpublic:

virtual void open( ) = 0;} ;ABC obj; //***** ERROR: ABC is an abstract class

Although an abstract base class cannot have objects instantiate it, such a class can have derived classes. A class derived from an abstract base class must override all of the base class's pure virtual methods; otherwise, the derived class itself becomes abstract and no objects can instantiate the derived class.

Page 8: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 8

EXAMPLE 5.4.3.

class ABC { // Abstract Base Classpublic:

virtual void open( ) = 0;} ;class X : public ABC { // 1st derived classpublic:

virtual void open( ) { /* … */ } // override open( )} ;class Y : public ABC { // 2nd derived class

//*** open is not overridden} ;ABC a1; // **** ERROR: ABC is abstractX x1; // **** Ok, X overrides open( ) and is not abstractY y1 // **** ERROR: Y is abstract—open( ) not defined

Page 9: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 9

DiscussionsDiscussionsClass X overrides the pure virtual method inherited from the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate it. By contrast, Y does not override the pure virtual method inherited from ABC. Therefore, Y becomes an abstract base class and cannot have objects instantiate it. One pure virtual method suffices to make a class an abstract base class. An abstract base class may have other methods that are not pure virtual or not even virtual at all. Further, an abstract base class may have data members. An abstract base class's members may be private, protected, or public.

Page 10: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 10

EXAMPLE 5.4.4.

class ABC { // Abstract Base Classpublic:

ABC( ) { /* … */ } // default constructorABC( int x ) { /* … */ } // general constructor~ABC( ) { /* */ } // destructorvirtual void open( ) = 0 ; // pure virtualvirtual void print( ) const { /* … */ } // virtualint getCount( ) const { return n; } // nonvirtual

private:int n; // data member

} ;

Page 11: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 11

DiscussionsDiscussions

ABC remains abstract, however, because it still has the pure virtual method open. Therefore, no objects can instantiate ABC.

Any class derived from ABC still must override open if the derived class is not to become abstract itself.

However, a derived class can simply use the inherited versions of print and getcount.

Page 12: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 12

Restrictions on Pure Functions

Only a virtual method can be pure. Neither a nonvirtual nor a top-level function can be declared pure virtual.

EXAMPLE 5.4.5.void f( ) = 0; //***** ERROR: not a virtual methodclass C {public:void open( ) = 0; //***** ERROR: not a virtual method} ;

Page 13: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 13

Uses of Abstract Base Classesclass BasicFile { // Abstract Base Classpublic:

// methods that any derived class should overridevirtual void open( ) = 0;virtual void close( ) = 0;virtual void flush( ) = 0;

} ;class InFile : public BasicFile {public:

virtual void open( ) { /* … */ } // definitionvirtual void close( ) { /* … */ } // definitionvirtual void flush( ) { /* … */ } // definition

} ;class OutFile : public BasicFile {public:

virtual void open( ) { /* … */ } // definitionvirtual void close( ) { /* … */ } // definitionvirtual void flush( ) { /* … */ } // definition

} ;

FIGURE 5.4.1 An abstract base class that specifies an interface shared by two derived classes.

Page 14: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 14

Run-Time Identification

C++ supports run-time type identification(RTTI), which provides mechanisms to• Check type conversions at run time.• Determine an object's type at run time.• Extend the RTTI provided by C++.

Page 15: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 15

The dynamic_cast Operator

In C++ a legal compile-time cast still may result in a run-time error. This danger may be particularly acute when a cast involves pointers or references to objects. The dynamic_cast operator can be used to test, at run time, when a cast involving objects is problematic.

Page 16: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 16

EXAMPLE 5.5.1.

class B {// . . .

} ;class D : public B {

// …} ;

int main( ) {/* 1 */ D* p; // pointer to derived class/* 2 */ p = new B; //***** ERROR: explicit cast needed/* 3 */ p = static_cast< D* >( new B ) ; // caution!//…

}

Page 17: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 17

DiscussionDiscussion

In general, it is a bad idea for a derived class pointer to point to a base class object. Nonetheless, this can be done with explicit casting. In line 3, we use a static_cast so that p can point to an object of the base class B. The static_cast in Example 5.5.1 is legal but dangerous. In particular, the cast may lead to a run-time error.

Page 18: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 18

EXAMPLE 5.5.2.

class B {public:

void f( ) { } // Note: no method m} ;class D : public B {public:

void m( ) { } // not in base class} ;int main( ) {

D* p; // *** pointer to derived classp = static_cast< D* >( new B ); // caution! p -> m( ) ; // ERROR: there is no B::m!// …

}

Page 19: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 19

Discussions

Base class B does not have a method named m. In main, the static_cast again allows p to point to a B object. There is no compile-time error from the method invocation

p->m();because p is of type D* and class D has the required method m.

Nonetheless, a run-time error results because p points to a Bobject-that is, to an object that has no method m.

We can summarize the problem illustrated in Example 5.5.2 by saying that the static_cast does not ensure type safety. The cast is not type safe because the method invocation

p->m( );generates a run-time error, although it is syntactically legal.

Page 20: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 20

Dynamic cast contDynamic cast cont’’dd

p's declared data type of D* implies that p can be used to invoke the method D: : m. The problem is that, at run time, p happens to point to a B object, which has no method m. C++ provides the dynamic_cast operator to check, at run time, whether a cast is type safe. A dynamic_cast has the same basic syntax as a static-cast. However, a dynamic_cast is legal only on a polymorphic type, that is, on a class that has at least one virtualmethod.

Page 21: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 21

EXAMPLE 5.5.3.class C {

// C has no virtual methods} ;class T {

// …} ;int main( ) {

dynamic_cast< T* >( new C ) ; // *** ERROR// …

}contains an error because it applies a dynamic_cast

to the nonpolymorphic type C. C is nonpolymorphicbecause it has no virtual methods.

Page 22: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 22

Correction

class C {public:

virtual void m( ) { } // C is now polymorphic} ;

The target type of a dynamic_cast, which is specified in angle brackets, must be a pointer or a reference. If T is a class, then T* and T& are legal targets for a dynamic_cast, but T is not.

Page 23: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 23

EXAMPLE 5.5.4.

class A { // polymorphic type// … A has a virtual method

} ;

class T { // target class// …

} ;int main( ) {

A a1;dynamic_cast< T >( a1 ) // *** ERROR// …

}

contains an error because the target type is T rather than, for example, T* or T&.

Page 24: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 24

EXAMPLE 5.5.5.class B {public:

virtual void f( ) { } // Note: no method m} ;class D : public B {public:

void m( ) { } // not in base class} ;int main( ) {

D* p = dynamic_cast< D* > ( new B) ;if ( p ) // is the cast type safe?

p->m( ); // if so, invoke p->m( )else

cerr << "Not safe for p to point to a B” << endl;// …

}

Page 25: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 25

DiscussionsWe initialize p, of type D*, to the value of a dynamic_cast. If T is a type and ptr is a pointer to a polymorphic type, then the expression

dynamic_cast< T* > ( ptr )evaluates to ptr, if the cast is type safe, and to zero (false), if the

cast is not type safe. In our example, the cast source is the expression new B, which evaluates to a non-NULL address if the new operation succeeds. So p would point to the dynamically allocated B object, if the dynamic_cast expression succeeded. If the cast expression failed, as it does in this case, then p is assigned NULL as its value.The dynamic_cast evaluates to NULL (false) precisely because we are trying to have the derived class pointer p point to the base class object created by new B. By checking the result of the dynamic_cast in the if statement, we avoid the run-time error.

Page 26: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 26

Summary of dynamic-cast and static-cast

C++ provides different casts for different purposes. A static_cast can be applied to any type, polymorphic or not. A dynamic_cast can be applied only to a polymorphictype, and the target type of a dynamic_cast must be a pointer or a reference. In these respects, a static_cast is more basic and general than a dynamic_cast. However, only a dynamic_cast can be used to check at run time whether a conversion is type safe. In this respect, a dynamic_cast is more powerful than a static_cast.

Page 27: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 27

COMMON PROGRAMMING ERRORS

1. It is an error to declare a top-level function virtual:virtual bool f( ); //***** ERROR: f is not a methodOnly methods can be virtual.

2. It is an error to declare a static method virtual:class C {public:

virtual void m( ) ; // ok, object methodvirtual static void s( ); //***** ERROR: static method

Page 28: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 28

COMMON PROGRAMMING ERRORS cont’d

3. If a virtual method is defined outside the class declaration, then the keyword virtual occurs in its declaration but not in its definition:

class C {public:

virtual void m1( ) { /* ... */ } // ok, decl + defvirtual void m2( ); // ok, declaration

} ;// *** ERROR:virtual should not occur in a definition// outside the class declarationvirtual void C::m2( ) {

// …}

Page 29: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 29

COMMON PROGRAMMING ERRORS cont’d

4. It is an error to declare any constructor virtual, although the destructor may be

virtual:class C {public:

virtual C( ); // *** ERROR: constructorvirtual C( int ) ; //*** ERROR: constructorvirtual ~C( ); // ok, destructor

} ;

Page 30: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 30

COMMON PROGRAMMING ERRORS cont’d

5. It is bad programming practice not to delete a dynamically created object before the object is inaccessible:

class C {// …

} ;void f( ) {

C* p = new C; // dynamically create a C object// … use it

} //****** ERROR: should delete the object!

Once control exits f , the object to which p points can no longer be accessed. Therefore, storage for this object ought to be freed:

void f ( ) {C* p = new C; // dynamically create a C object

// .... use itdelete p; // delete it}

Page 31: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 31

COMMON PROGRAMMING ERRORS cont’d

6. If a method hides an inherited method, then it is an error to try to invoke the inherited method without using its full name:

class A {public:

void m( int ) { /* … */ } // takes 1 arg} ;class Z : public A {public;

void m( ) { /* … */ } // takes 0 args, hides A::m} ;int main( ) {

Z z1;z1.m( -999 ) ; // ERROR: Z::m hides A::mz1.A::m( -999 ) // ok, full namez1.m( ); // ok, local method// …

}The error remains even if m is virtual because A: :m and Z: :m do not have the

same signature.

Page 32: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 32

COMMON PROGRAMMING ERRORS cont’d7. It is an error to expect run-time binding of nonvirtual methods. In the code segmentclass A {public:

void m( ) { cout << "A::m" << endl; }} ;class Z : public A {public:

void m( ) { cout << "Z::m”, << endl ; }} ;int main( ) {

A* p = new Z; // ok, p points to Z objectp->m(); // prints A::m, not Z::m// …

}as m is not virtual.

Because compile-time binding is in effect, the call p->m( ); is to A: m since p's data type is A*. It is irrelevant that p happens to point to a Z object.If we make m a virtual method

class A {public:

virtual void m( ) { cout << "A::m " << endl; }} ;

then the output is Z: :m because run-time binding is in effect and p points to a Z object.

Page 33: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 33

COMMON PROGRAMMING ERRORS cont’d

8. It is an error to expect a derived class virtual method D : : m to override a base class virtual method B: :m if the two methods have different signatures. The code segment

class A {public:

virtual void m( ); // base class virtual method} ;class Z : public A {public:

//***** Caution: Z::m hides A::mvirtual void m( int ) ; // derived class virtual method

} ;

has two virtual methods named m, but Z: :m does not override A: :m because the two methods have different signatures. For useful polymorphism to occur, the virtual methods must have the same signature, not just the same name. In this example, the two virtual methods are completely unrelated. They simply happen to share a name.

Page 34: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 34

COMMON PROGRAMMING ERRORS cont’d9. It is an error to try to define objects that instantiate an abstract base class:class ABC { // abstract base classpublic:

virtual void m( ) = 0; // pure virtual method} ;ABC a1; //***** ERROR: ABC is abstract

10. If a class C is derived from an abstract base class ABC and C does not override all of ABC's pure virtual methods, then C is abstract and cannot have objects instantiate it:

class ABC { // abstract base classpublic:

virtual void m1( ) = 0; // pure virtual methodvirtual void m2( ) = 0; // pure virtual method

} ;class C : public ABC {public:

virtual void m1( ) { /* */ } // override m1// m2 not overridden

} ;C c1; //***** ERROR: C is abstract

Page 35: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 35

COMMON PROGRAMMING ERRORS cont’d

11. A dynamic-cast may be applied only to a polymorphic type, that is, a class with at least one virtual method. Therefore, the following code segment is in error:

class C {//... no virtual methods

} ;int main( ) {

//***** ERROR: C is not polymorphicdynamic_cast< void* >( new C ) ;// …

}

Page 36: Abstract Classes Static and Dynamic Casting Common ...natacha/TeachFall_2010/CSC330/... · the abstract base class ABC. Therefore, X is not abstract and may have objects instantiate

CSC 330 OO Software Design 36

COMMON PROGRAMMING ERRORS cont’d12. The target type of a dynamic_cast (that is, the expression in

angle brackets) must be a pointer or a reference. Therefore, the following code segment is in error:

class C {public:

virtual void m( ) { }} ;class A {

// …} ;int main( ) {

C c1;//***** ERROR: target type must a pointer or referenceA a1 = dynamic_cast< A >( c1 ) ;// …

}