First | Next | Previous | Last | Glossary | About

# Compounding objects, that is, Composite Classes - Part 2

- Introduction
- Tutorial 1

## Introduction

In the previous session I mentioned, in passing, that the example didn't use constructors and destructors and I used an initialisation method for the powersupply class (and the case class in the sample answer). This is neither an efficient way to construct a composite class nor a reasonable way. Nobody constructs a tv and then adds the bits to it. It makes more sense to complete the tv when it is constructed.

The next example uses constructors for the power supply and the case.

    #include <iostream>
    #define MAXLEVEL 100
    #define MINLEVEL 0

    typedef enum toggleswitch {OFF = 0, ON = 1};
    typedef enum powertype    {LINEAR, SWITCHED, SOLAR,
                               LEADACID, STEAM};
    typedef enum casetype     {PLASTIC, CARDBOARD, MASONITE};
    const char *SupplyDesc[] = {"Linear", "Switched", "Solar",
                                "Lead Acid", "Steam"};
    const char *CaseDesc[]   = {"Plastic", "Cardboard",
                                "Masonite"};
    const char *PS = " power supply is ";
    const char *CS = " and the case material is ";
    const char *VS = "The volume is ";

The first part is much the same as before except that I have added the various declarations for the case.

I've followed the same pattern as before, an enum and a set of matching accessories in the form of an array of strings. These are the nearest things to eye-candy in unwindowed C++.

Now for the modifications to the classes.

    class TCaseType
    { public:
       TCaseType(casetype);
       casetype GetCaseType();
      protected:
      private:
       casetype caseMaterial;
    };

    class TPowerSupply
    { public:
       TPowerSupply(powertype);
       powertype GetSupplyType();
      private:
       powertype supply;
    };

If you compare these declarations with those in the previous lesson you will see that the Set.... member functions are missing, instead each class has a constructor which has a single parameter.

Everything else in the power supply and case classes is unchanged. The TV class is largely unchanged except that the InitTV method has been removed since we don't need this any more. The initialisation of the tv instance is now done by the constructor.

Since the changes to TVModel are minimal I haven't shown it here. There is a complete listing of the program at the end of this session. You can run it through it's paces and use it for the tutorial work.

    TVModel::TVModel(toggleswitch t,int v,
                     int cn, int col,
                     int b, int c, powertype p,
                     casetype ct
                    ) : supply(p), tvCase(ct)
    { bOnOffSwitch    = t;
      nVolumeLevel    = v;
      nChannelNumber  = cn;
      nColour         = col;
      nBrightness     = b;
      nContrast       = c;
      nNumber++;
    }

    TPowerSupply::TPowerSupply(powertype p)
    {
     supply = p;
    }

    TCaseType::TCaseType(casetype c)
    {
     caseMaterial = c;
    }

The way in which the constructors are used is likely to slip by if you don't look too closely.

Did you notice the addition of:
`: supply(p), tvCase(ct)`
to the declaration of the TVModel?

The constructors for the power supply member and the case member in the tv class are called before the initialisation of the tv instance takes place. The constructors are member initialisers.

You should use this technique for initialising composed objects as a matter of course.

## Tutorial 1

Here is some tutorial work for you.

1 Try the example, which follows just below, to see that it works.

2 .

    #include <iostream>
    #define MAXLEVEL 100
    #define MINLEVEL 0

    typedef enum toggleswitch {OFF = 0, ON = 1};
    typedef enum powertype    {LINEAR, SWITCHED, SOLAR,
                               LEADACID, STEAM};
    typedef enum casetype     {PLASTIC, CARDBOARD, MASONITE};
    const char *SupplyDesc[] = {"Linear", "Switched", "Solar",
                                "Lead Acid", "Steam"};
    const char *CaseDesc[]   = {"Plastic", "Cardboard",
                                "Masonite"};
    const char *PS = " power supply is ";
    const char *CS = " and the case material is ";
    const char *VS = "The volume is ";

    class TCaseType
    { public:
       TCaseType(casetype);
       casetype GetCaseType();
      protected:
      private:
       casetype caseMaterial;
    };

    class TPowerSupply
    { public:
       TPowerSupply(powertype);
       powertype GetSupplyType();
      private:
       powertype supply;
    };

    class TVModel
    { public:
       TVModel(toggleswitch,int,int,int,int,
               int,powertype,casetype);
       void  OnOff();
       toggleswitch IsOn();
       void AdjustVolume(int Level);
       int  GetVolume();
       powertype GetSupplyType();
       casetype  GetCaseType();
       static int GetNumberTVs()
        { return nNumber; }

      protected:
       toggleswitch bOnOffSwitch;
       int nVolumeLevel,
           nChannelNumber,
           nColour,
           nBrightness,
           nContrast;
       static int nNumber;
       TPowerSupply supply;
       TCaseType    tvCase;
      private:
    };

    TVModel::TVModel(toggleswitch t,int v, int cn, int col,
                     int b, int c, powertype p,
                     casetype ct
                    ) : supply(p), tvCase(ct)
    { bOnOffSwitch    = t;
      nVolumeLevel    = v;
      nChannelNumber  = cn;
      nColour         = col;
      nBrightness     = b;
      nContrast       = c;
      nNumber++;
    }

    void TVModel::OnOff()
    {if (bOnOffSwitch == ON)
      bOnOffSwitch = OFF;
     else
     if (bOnOffSwitch == OFF)
      bOnOffSwitch = ON;
    }

    toggleswitch TVModel::IsOn()
    { return bOnOffSwitch; }

    void TVModel::AdjustVolume(int Level)
    { if (IsOn())
       if ((Level < MAXLEVEL) && (Level > MINLEVEL))
        nVolumeLevel = Level;
    }

    int TVModel::GetVolume()
    {
     return nVolumeLevel;
    }

    powertype TVModel::GetSupplyType()
    {
     return supply.GetSupplyType();
    }

    casetype TVModel::GetCaseType()
    {
     return tvCase.GetCaseType();
    }

    int TVModel::nNumber = 0;

    TPowerSupply::TPowerSupply(powertype p)
    {
      supply = p;
    }

    powertype TPowerSupply::GetSupplyType()
    {
     return supply;
    }

    TCaseType::TCaseType(casetype c)
    {
     caseMaterial = c;
    }

    casetype TCaseType::GetCaseType()
    {
      return caseMaterial;
    }

    void msgCount(TVModel, const char *);
    void msgInfo(TVModel);

    int main()
    {  TVModel Sony(OFF,10,5,4,3,2, LINEAR, PLASTIC),
               Akai(OFF,23,42,0,0,0, SWITCHED, PLASTIC),
               DRB(OFF,100,100,0,0,0, STEAM, MASONITE);
       msgCount(DRB,"We have ");
       msgInfo(Sony);
       msgInfo(Akai);
       msgInfo(DRB);
       return 0;
    }

    void msgCount(TVModel T, const char * mMsg)
    {cout << mMsg << T.GetNumberTVs()
          << " tv's " << endl;
    }

    void msgInfo(TVModel T)
    {
     cout << VS
          << T.GetVolume()
          << PS
          << SupplyDesc[T.GetSupplyType()]
          << CS
          << CaseDesc[T.GetCaseType()]
          << endl;
    }

First | Next | Previous | Last | Glossary | About

Copyright © 1999 - 2001 David Beech