• The derived-class constructor should pass base-class information to a base-class constructor via a member initializer list.

• The derived-class constructor should initialize the data members that were added to the derived class.

This example doesn’t provide explicit destructors, so the implicit destructors are used. Destroying an object occurs in the opposite order used to construct an object. That is, the body of the derived-class destructor is executed first, and then the base-class destructor is called automatically.

Note

When creating an object of a derived class, a program first calls the base-class constructor and then calls the derived-class constructor. The base-class constructor is responsible for initializing the inherited data members. The derived-class constructor is responsible for initializing any added data members. A derived-class constructor always calls a base-class constructor. You can use the initializer list syntax to indicate which base-class constructor to use. Otherwise, the default base-class constructor is used.

When an object of a derived class expires, the program first calls the derived-class destructor and then calls the base-class destructor.

Member Initializer Lists

A constructor for a derived class can use the initializer list mechanism to pass values along to a base-class constructor. Consider this example:

derived::derived(type1 x, type2 y) : base(x,y) // initializer list

{

    ...

}

Here, derived is the derived class, base is the base class, and x and y are variables used by the base-class constructor. If, say, the derived-class constructor receives the arguments 10 and 12, this mechanism then passes 10 and 12 on to the base-class constructor defined as taking arguments of these types. Except for the case of virtual base classes (see Chapter 14, “Reusing Code in C++”), a class can pass values back only to its immediate base class. However, that class can use the same mechanism to pass back information to its immediate base class, and so on. If you don’t supply a base-class constructor in a member initializer list, the program uses the default base-class constructor. The member initializer list can be used only in constructors.

Using a Derived Class

To use a derived class, a program needs access to the base-class declarations. Listing 13.4 places both class declarations in the same header file. You could give each class its own header file, but because the two classes are related, it makes more organizational sense to keep the class declarations together.

Listing 13.4. tabtenn1.h

// tabtenn1.h -- a table-tennis base class

#ifndef TABTENN1_H_

#define TABTENN1_H_

#include

using std::string;

// simple base class

class TableTennisPlayer

{

private:

    string firstname;

    string lastname;

    bool hasTable;

public:

    TableTennisPlayer (const string & fn = "none",

                       const string & ln = "none", bool ht = false);

    void Name() const;

    bool HasTable() const { return hasTable; };

    void ResetTable(bool v) { hasTable = v; };

};

// simple derived class

class RatedPlayer : public TableTennisPlayer

{

private:

    unsigned int rating;

public:

    RatedPlayer (unsigned int r = 0, const string & fn = "none",

                 const string & ln = "none", bool ht = false);

    RatedPlayer(unsigned int r, const TableTennisPlayer & tp);

    unsigned int Rating() const { return rating; }

    void ResetRating (unsigned int r) {rating = r;}

};

#endif

Listing 13.5 provides the method definitions for both classes. Again, you could use separate files, but it’s simpler to keep the definitions together.

Listing 13.5. tabtenn1.cpp

//tabtenn1.cpp -- simple base-class methods

#include "tabtenn1.h"

#include

TableTennisPlayer::TableTennisPlayer (const string & fn,

    const string & ln, bool ht) : firstname(fn),

        lastname(ln), hasTable(ht) {}

void TableTennisPlayer::Name() const

{

    std::cout << lastname << ", " << firstname;

}

// RatedPlayer methods

RatedPlayer::RatedPlayer(unsigned int r, const string & fn,

     const string & ln, bool ht) : TableTennisPlayer(fn, ln, ht)

{

    rating = r;

}

RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & tp)

    : TableTennisPlayer(tp), rating(r)

{

}

Listing 13.6 creates objects of both the TableTennisPlayer class and the RatedPlayer class. Notice that objects of both classes can use the TableTennisPlayer class Name() and HasTable() methods.

Listing 13.6. usett1.cpp

// usett1.cpp -- using base class and derived class

#include

#include "tabtenn1.h"

int main ( void )

{

    using std::cout;

    using std::endl;

    TableTennisPlayer player1("Tara", "Boomdea", false);

    RatedPlayer rplayer1(1140, "Mallory", "Duck", true);

    rplayer1.Name();          // derived object uses base method

    if (rplayer1.HasTable())

        cout << ": has a table.\n";

    else

        cout << ": hasn't a table.\n";

    player1.Name();           // base object uses base method

    if (player1.HasTable())

        cout << ": has a table";

    else

        cout << ": hasn't a table.\n";

    cout << "Name: ";

    rplayer1.Name();

    cout << "; Rating: " << rplayer1.Rating() << endl;

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги