1. Trang chủ
  2. » Công Nghệ Thông Tin

A Complete Guide to Programming in C++ part 60 doc

10 198 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 221,22 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

䊐 Concrete or Abstract?If a class comprises pure virtual methods, you cannot create objects of this class type.. 䊐 Deriving Abstract Classes When a class is derived from an abstract clas

Trang 1

䊐 Concrete or Abstract?

If a class comprises pure virtual methods, you cannot create objects of this class type

Example: Coworker worker("Black , Michael");

The compiler will issue an error message here, as the Coworkerclass contains the pure virtual method income() This avoids calling a method for worker that still needs to be defined

A class that does not allow you to create any objects is referred to as an abstract class.

In contrast, a class that allows you to create objects is referred to as a concrete class.

䊐 Deriving Abstract Classes

When a class is derived from an abstract class, it inherits all the methods the base class contains, particularly the pure virtual methods If all of these pure virtual methods are implemented in the derived class, you can then create an object of the derived class type

This means you need to implement the income() method in the Laborer class shown opposite Since the hourly wage and the number of hours worked are both defined for blue-collar workers, it is possible to implement that method

Example: double Laborer::income()

{ return ( wages * hr );

}

A class derived from a concrete class can again contain pure virtual methods, due to additional definitions in the derived class In other words, an abstract class can be derived from a concrete class

An abstract class does not necessarily need to contain pure virtual functions If the class contains a protected constructor, objects of the class type cannot be created The constructor can only be called then by methods in derived classes A constructor of this type normally acts as base initializer, when an object of a derived class type is cre-ated

A class with pure virtual methods is an abstract class

NOTE

A class derived from a class containing pure virtual methods is a concrete class, if it contains a definition for each pure virtual function

NOTE

Trang 2

570 C H A P T E R 2 6 A B S T R A C T C L A S S E S

// coworker.h: Extending the headerfile

//

-class Employee : public Coworker

{

private:

double salary; // Pay per month

public:

Employee( const string& s="", double sa = 0.0)

: Coworker(s), salary(g){ } double getSalary() const { return salary; } void setSalary( double sa){ salary = sa; } void display() const;

double income()const { return salary; }

Employee& operator=( const Coworker& );

Employee& operator=( const Employee& );

};

// coworker_t.cpp : Using the Coworker classes

//

-#include "coworker.h"

int main() {

Coworker* felPtr[2];

felPtr[0] = new Laborer("Young, Neil",45., 40); felPtr[1] = new Employee("Smith, Eve", 3850.0);

for( int i = 0; i < 2; ++i) {

felPtr[i]->display();

cout << "\nThe income of " << felPtr[i]->getName()

<< " : " << felPtr[i]->income() << endl;

} delete felPtr[0]; delete felPtr[1];

return 0;

}

The derived class Employee

Sample program

Trang 3

Although you cannot define objects for abstract classes, you can declare pointers and ref-erences to abstract classes

Example: Coworker *felPtr, &coRef;

The pointer felPtris a base class pointer that can address objects belonging to derived concrete classes The reference coRefcan also address objects of this type

䊐 References to Abstract Base Classes

References to base classes are often used as parameters in functions The copy construc-tor in the Coworkerclass is just one of them

Example: Coworker( const Coworker& );

The copy constructor expects an object belonging to a derived class, since the base class

is abstract

The assignment in the Coworkerclass has a reference as a parameter and returns a reference to the abstract class

䊐 Pointers to Abstract Base Classes

Pointers to base classes are generally used to address dynamically allocated objects If the base class is abstract, you can only allocate memory for objects belonging to derived, con-crete classes

Example: Coworker* felPtr;

felPtr = new Laborer("Young, Neil",45.,40);

cout << felPtr->income();

Since the income()method is virtual, a corresponding function found in the derived classLaboreris executed

䊐 Polymorphic Interface

Defining pure virtual methods also determines interfaces for general operations, although the interfaces still need to implemented in the derived classes If a derived class contains its own definition of a virtual method, this version will also be executed if an object is referenced by a base class pointer or reference Abstract classes are therefore also referred

to as polymorphic interfaces to derived classes.

The opposite page shows the definition of the Employee class, which was also derived from the abstract class Coworker The operator functions for the assignments are discussed and implemented in the following section

Trang 4

572 C H A P T E R 2 6 A B S T R A C T C L A S S E S

// Virtual Assignment in the base class

Coworker& operator=(const Coworker & m)

{ if( this != &m ) // No self assignment name = m.name;

return *this;

}

Redefining the virtual operator function operator=(), which returns a reference to the derived class,

is not yet supported by all compilers In this case the return type must be a reference to the base class

Coworker

NOTE

// Redefinition: virtual

Employee& operator=(const Coworker& m)

{ if( this != &m ) // No self assignment {

Coworker::operator=( m );

salary = 0.0;

} return *this;

}

// Standard Assignment: not virtual

Employee& operator=(const Employee& a)

{ if( this != &a ) {

Coworker::operator=( a );

salary = a.salary;

} return *this;

}

Assignment for class Coworker

Assignments for class Employee

Trang 5

䊐 Virtual Operator Functions

Operator functions implemented as methods can also be virtual In this case, you can ensure that the right version of an operator function will be executed when using a pointer or reference to a base class to address a derived class object

One example of this is the operator function for an assignment If the function decla-ration is not virtual, and if the function is called via a base class pointer, only the base data of the object is overwritten Any additional data members of the derived class remain unchanged

䊐 Using Virtual Assignments

The assignment was declared virtual in the Coworker base class The derived classes LaborerandEmployeeboth contain their own versions Thus, in the following

Example: void cpy(Coworker& a,const Coworker& b)

{ a = b; }

the assignment of the Employeeclass is executed, if an object of this class type is the first argument passed to it If the object is a Laborer type, the assignment of the Laborerclass is performed

In the case of the cpy()function, you can therefore assign two objects of any class, including classes derived at a later stage, without having to modify the function itself! However, you definitely need to define a version of the assignment for each derived class

䊐 Redefining the Standard Assignment

When you define a new version for a virtual method in a derived class, this implies using the signature of the original method Since the standard assignment of a derived class has

a signature of its own, it is not virtual The standard assignment for the Laborerclass has the following prototype:

Example: Laborer& operator=(const Laborer&);

The type const Laborer& is different from the const Coworker& type of the parameter in the virtual operator function of the base class The standard assignment thus masks the virtual assignment in the base class This gives rise to two issues:

■ the virtual operator function for the assignment must be defined for every derived class

■ to ensure that the standard assignment is also available, the standard assignment must also be redefined in every derived class

Trang 6

574 C H A P T E R 2 6 A B S T R A C T C L A S S E S

// cell.h: Defining the classes Cell, BaseEl, and DerivedEl //

-#ifndef _CELL_

#define _CELL_

#include <string>

#include <iostream>

using namespace std;

class Cell

{

private:

Cell* next;

protected:

Cell(Cell* suc = NULL ){ next = suc; }

public:

virtual ~Cell(){ } // Access methods to be declared here

virtual void display() const = 0;

};

class BaseEl : public Cell

{

private:

string name;

public:

BaseEl( Cell* suc = NULL, const string& s = "") : Cell(suc), name(s){}

// Access methods would be declared here

void display() const;

};

class DerivedEl : public BaseEl

{

private:

string rem;

public:

DerivedEl(Cell* suc = NULL,const string& s="",

const string& b="") : BaseEl(suc, s), rem(b) { } // Access methods would be declared here

void display() const;

};

#endif

The abstract base class Cell and derived classes

Trang 7

1st list element

Info Info

Pointer

2nd list element 3rd list element Info

Pointer Pointer

䊐 Terminology

Let’s look into implementing an application that uses an inhomogeneous list An inho-mogeneous list is a linear list whose elements can be of different types If the data you need to store consists of objects in a class hierarchy, one list element could contain an object belonging to the base class, whereas another could contain an object of a derived class

Due to implicit type conversions in class hierarchies, you can use the base class point-ers to manage the list elements, that is, you can manage the elements in a linked list The following graphic illustrates this scenario:

䊐 Representing List Elements

To separate the management of list elements from the information contained in the list,

we have defined an abstract class called Cell as a base class for all list elements The class contains a pointer of type Cell* as the data member used to link list elements Since Cell type objects are not be created, the constructor in the Cell class has a protecteddeclaration

The Cellclass does not contain any data that might need to be output However, each class derived from Cellcontains data that need to be displayed For this reason, Cellcontains a declaration of the pure virtual method display(), which can be mod-ified for multiple derivations

The classes BaseEl andDerivedEl, which are derived from Cell, represent list elements used for storing information To keep things simple, the BaseElclass contains only a name, and the DerivedElclass additionally contains a comment The public declaration section contains a constructor and access method declarations In addition, a suitable version of the display() method is defined Both classes are thus concrete classes

Trang 8

576 C H A P T E R 2 6 A B S T R A C T C L A S S E S

Info Info Pointer

New element:

Info Pointer Pointer Info

// List.h: Defining the class InhomList //

-#ifndef _LIST_H

#define _LIST_H

#include "cell.h"

class InhomList

{ private:

Cell* first;

protected:

Cell* getPrev(const string& s);

void insertAfter(const string& s,Cell* prev);

void insertAfter(const string& s,

const string& b,Cell* prev);

public: // Constructor, Destructor etc

void insert(const string& n);

void insert(const string& n, const string& b);

void displayAll() const;

};

#endif

void InhomList::insertAfter(const string& s, Cell* prev) {

if( prev == NULL ) // Insert at the beginning, first = new BaseEl( first, s);

else // middle, or end

{ Cell* p = new BaseEl(prev->getNext(), s);

prev->setNext(p);

} }

Defining class InhomList

Inserting a list element in the middle

Definition of insertAfter() version

Trang 9

䊐 The InhomList Class

The inhomogeneous list must allow sorted insertion of list elements It is no longer suffi-cient to append elements to the end of the list; instead, the list must allow insertion at any given point A pointer to the first element in the list is all you need for this task You can then use the pointer to the next list element to access any given list element The definition of the InhomList class is shown opposite A pointer to Cell has been declared as a data member The constructor has very little to do It simply sets the base class pointer to NULL, thus creating an empty list

The list will be sorted by name When inserting a new element into the list, the inser-tion point—that is the posiinser-tion of the element that will precede the new element—must first be located In our example, we first locate the immediate lexicographical predeces-sor The getPrev()method, shown opposite, performs the search and returns either the position of the predecessor or NULL if there is no predecessor In this case, the new list element is inserted as the first element in the list

䊐 Inserting a New List Element

After finding the insertion position you can call the insertAfter()method that allo-cates memory for a new list element and inserts the element into the list There are two cases that need to be looked at:

1 If the new element has to be inserted at the start of the list, what was originally the first element now becomes the second The new element becomes the first element The firstpointer thus needs updating

2 If the new element is inserted at any other position in the list, the firstpointer

is not affected Instead, you have to modify two pointers The pointer in the pre-ceding list element must be pointed at the new element and the pointer in the new element must be pointed at what was formerly the successor of the preceding element This situation also applies in cases where the successor was a NULL pointer, in other words, when the new element is appended to the list

Since the list contains objects of the BaseEl and DerivedEl types, the insertAfter()method has been overloaded with two versions They differ only in different calls to the newoperator

Theinsert()method was overloaded for the same reason Both versions first call the getPrev() method and the corresponding version of the insertAfter() method

Trang 10

578 C H A P T E R 2 6 A B S T R A C T C L A S S E S

class InhomList

{

private:

Cell* first;

protected:

Cell* getPrev(const string& s);

Cell* getPos(const string& s);

void insertAfter(const string& s, Cell* prev); void insertAfter(const string& s,const string& b,

Cell* prev);

void erasePos(Cell* pos);

public:

InhomList(){ first = NULL; } InhomList(const InhomList& src);

~InhomList();

InhomList& operator=( const InhomList& src);

void insert(const string& n);

void insert(const string& n, const string& b); void erase(const string& n);

void displayAll() const;

};

The complete class InhomList

Ngày đăng: 06/07/2014, 17:21

TỪ KHÓA LIÊN QUAN