As usual, the class makes the data members private. This implies that the Student class member functions can use the public interfaces of the string and valarray classes to access and modify the name and scores objects, but the outside world cannot do so. The only access the outside world will have to name and scores is through the public interface defined for the Student class (see Figure 14.1). A common way of describing this is to say that the Student class acquires the implementation of its member objects but doesn’t inherit the interface. For example, a Student object uses the string implementation rather than a char * name or a char name[26] implementation for holding the name. But a Student object does not innately have the ability to use the string operator+=() function for appending.

Figure 14.1. Objects within objects: containment.

Interfaces and Implementations

With public inheritance, a class inherits an interface, and, perhaps, an implementation. (Pure virtual functions in a base class can provide an interface without an implementation.) Acquiring the interface is part of the is-a relationship. With composition, on the other hand, a class acquires the implementation without the interface. Not inheriting the interface is part of the has-a relationship.

The fact that a class object doesn’t automatically acquire the interface of a contained object is a good thing for a has-a relationship. For example, string overloads the + operator to allow concatenating two strings, but, conceptually, it doesn’t make sense to concatenate two Student objects. That’s one reason not to use public inheritance in this case. On the other hand, parts of the interface for the contained class may make sense for the new class. For example, you might want to use the operator<() method from the string interface to sort Student objects by name. You can do so by defining a Student::operator<() member function that internally uses the string::operator<() function. Let’s move on to some details.

The Student Class Example

At this point you need to provide the Student class declaration. It should, of course, include constructors and at least a few functions to provide an interface for the Student class. Listing 14.1 does this, defining all the constructors inline. It also supplies some friends for input and output.

Listing 14.1. studentc.h

// studentc.h -- defining a Student class using containment

#ifndef STUDENTC_H_

#define STUDENTC_H_

#include

#include

#include

class Student

{

private:

    typedef std::valarray ArrayDb;

    std::string name;       // contained object

    ArrayDb scores;         // contained object

    // private method for scores output

    std::ostream & arr_out(std::ostream & os) const;

public:

    Student() : name("Null Student"), scores() {}

    explicit Student(const std::string & s)

        : name(s), scores() {}

    explicit Student(int n) : name("Nully"), scores(n) {}

    Student(const std::string & s, int n)

        : name(s), scores(n) {}

    Student(const std::string & s, const ArrayDb & a)

        : name(s), scores(a) {}

    Student(const char * str, const double * pd, int n)

        : name(str), scores(pd, n) {}

    ~Student() {}

    double Average() const;

    const std::string & Name() const;

    double & operator[](int i);

    double operator[](int i) const;

// friends

    // input

    friend std::istream & operator>>(std::istream & is,

                                     Student & stu);  // 1 word

    friend std::istream & getline(std::istream & is,

                                  Student & stu);     // 1 line

    // output

    friend std::ostream & operator<<(std::ostream & os,

                                     const Student & stu);

};

#endif

In order to simplify notation, the Student class contains this typedef:

typedef std::valarray ArrayDb;

This enables the remaining code to use the more convenient notation ArrayDb instead of std::valarray. Thus, methods and friends can refer to the ArrayDb type. Placing this typedef in the private portion of the class definition means that it can be used internally in the Student implementation but not by outside users of the Student class.

Note the use of the keyword explicit:

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

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

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