Constructors and Destructors

Dog objects are Mammal objects. This is the essence of the is-a relationship. When Fido is created, his base constructor is called first, creating a Mammal. Then the Dog constructor is called, completing the construction of the Dog object. Because we gave Fido no parameters, the default constructor was called in each case. Fido doesn't exist until he is completely constructed, which means that both his Mammal part and his Dog part must be constructed. Thus, both constructors must be called.

When Fido is destroyed, first the Dog destructor will be called and then the destructor for the Mammal part of Fido. Each destructor is given an opportunity to clean up after its own part of Fido. Remember to clean up after your Dog! Listing 16.3 demonstrates this.

Listing 16.3. Constructors and Destructors Called
 0:  //Listing 16.3 Constructors and destructors called.
 1:  #include <iostream>
 2:
 3:  enum BREED { YORKIE, CAIRN, DANDIE, SHETLAND, DOBERMAN, LAB };
 4:
 5:  class Mammal
 6:  {
 7:  public:
 8:      // constructors
 9:      Mammal();
10:      ~Mammal();
11:
12:      //accessors
13:      int GetAge() const { return itsAge; }
14:      void SetAge(int age) { itsAge = age; }
15:      int GetWeight() const { return itsWeight; }
16:      void SetWeight(int weight) { itsWeight = weight; }
17:
18:      //Other methods
19:      void Speak() const { std::cout << "Mammal sound!
"; }
20:      void Sleep() const { std::cout << "shhh. I'm sleeping.
"; }
21:
22:  protected:
23:      int itsAge;
24:      int itsWeight;
25:  };
26:
27:  class Dog : public Mammal
28:  {
29:  public:
30:      // Constructors
31:      Dog();
32:      ~Dog();
33:
34:      // Accessors
35:      BREED GetBreed() const { return itsBreed; }
36:      void SetBreed(BREED breed) { itsBreed = breed; }
37:
38:      // Other methods
39:      void WagTail() { std::cout << "Tail wagging...
"; }
40:      void BegForFood() { std::cout << "Begging for food...
"; }
41:
42:  private:
43:      BREED itsBreed;
44:  };
45:
46:  Mammal::Mammal():
47:  itsAge(1),
48:  itsWeight(5)
49:  {
50:      std::cout << "Mammal constructor...
";
51:  }
52:
53:  Mammal::~Mammal()
54:  {
55:      std::cout << "Mammal destructor...
";
56:  }
57:
58:  Dog::Dog():
59:  itsBreed(YORKIE)
60:  {
61:      std::cout << "Dog constructor...
";
62:  }
63:
64:  Dog::~Dog()
65:  {
66:      std::cout << "Dog destructor...
";
67:  }
68:
69:  int main()
70:  {
71:      Dog fido;
72:      fido.Speak();
73:      fido.WagTail();
74:      std::cout << "Fido is " << fido.GetAge() << " years old
";
75:      return 0;
76:  }


Mammal constructor...
Dog constructor...
Mammal sound!
Tail wagging...
Fido is 1 years old
Dog destructor...
Mammal destructor...
					

Listing 16.3 is just like Listing 16.2, except that the constructors and destructors now print to the screen when called. Mammal's constructor is called, and then Dog's. At that point the Dog fully exists, and its methods can be called. When Fido goes out of scope, Dog's destructor is called, followed by a call to Mammal's destructor.

Passing Arguments to Base Constructors

It is possible that you'll want to overload the constructor of Mammal to take a specific age, and that you'll want to overload the Dog constructor to take a breed. How do you get the age and weight parameters passed up to the right constructor in Mammal? What if Dogs want to initialize weight but Mammals don't?

Base class initialization can be performed during class initialization by writing the base class name followed by the parameters expected by the base class. Listing 16.4 demonstrates this.

Listing 16.4. Overloading Constructors in Derived Classes
  0:  //Listing 16.4 Overloading constructors in derived classes
  1:  #include <iostream>
  2:
  3:  enum BREED { YORKIE, CAIRN, DANDIE, SHETLAND, DOBERMAN, LAB };
  4:
  5:  class Mammal
  6:  {
  7:  public:
  8:      // constructors
  9:      Mammal();
 10:      Mammal(int age);
 11:      ~Mammal();
 12:
 13:      //accessors
 14:      int GetAge() const { return itsAge; }
 15:      void SetAge(int age) { itsAge = age; }
 16:      int GetWeight() const { return itsWeight; }
 17:      void SetWeight(int weight) { itsWeight = weight;   }
 18:
 19:      //Other methods
 20:      void Speak() const { std::cout << "Mammal sound!
"; }
 21:      void Sleep() const { std::cout << "shhh. I'm sleeping.
"; }
 22:
 23:  protected:
 24:      int itsAge;
 25:      int itsWeight;
 26:  };
 27:
 28:  class Dog : public Mammal
 29:  {
 30:  public:
 31:      // Constructors
 32:      Dog();
 33:      Dog(int age);
 34:      Dog(int age, int weight);
 35:      Dog(int age, BREED breed);
 36:      Dog(int age, int weight, BREED breed);
 37:      ~Dog();
 38:
 39:      // Accessors
 40:      BREED GetBreed() const { return itsBreed; }
 41:      void SetBreed(BREED breed) { itsBreed = breed; }
 42:
 43:      // Other methods
 44:      void WagTail() { std::cout << "Tail wagging...
"; }
 45:      void BegForFood() { std::cout << "Begging for food...
"; }
 46:
 47:  private:
 48:      BREED itsBreed;
 49:  };
 50:
 51:  Mammal::Mammal():
 52:  itsAge(1),
 53:  itsWeight(5)
 54:  {
 55:      std::cout << "Mammal constructor...
";
 56:  }
 57:
 58:  Mammal::Mammal(int age):
 59:  itsAge(age),
 60:  itsWeight(5)
 61:  {
 62:      std::cout << "Mammal(int) constructor...
";
 63:  }
 64:
 65:  Mammal::~Mammal()
 66:  {
 67:      std::cout << "Mammal destructor...
";
 68:  }
 69:
 70:  Dog::Dog():
 71:  Mammal(),
 72:  itsBreed(YORKIE)
 73:  {
 74:      std::cout << "Dog constructor...
";
 75:  }
 76:
 77:  Dog::Dog(int age):
 78:  Mammal(age),
 79:  itsBreed(YORKIE)
 80:  {
 81:      std::cout << "Dog(int) constructor...
";
 82:  }
 83:
 84:  Dog::Dog(int age, int weight):
 85:  Mammal(age),
 86:  itsBreed(YORKIE)
 87:  {
 88:      itsWeight = weight;
 89:      std::cout << "Dog(int, int) constructor...
";
 90:  }
 91:
 92:  Dog::Dog(int age, int weight, BREED breed):
 93:  Mammal(age),
 94:  itsBreed(breed)
 95:  {
 96:      itsWeight = weight;
 97:      std::cout << "Dog(int, int, BREED) constructor...
";
 98:  }
 99:
100:  Dog::Dog(int age, BREED breed):
101:  Mammal(age),
102:  itsBreed(breed)
103:  {
104:      std::cout << "Dog(int, BREED) constructor...
";
105:  }
106:
107:  Dog::~Dog()
108:  {
109:      std::cout << "Dog destructor...
";
110:  }
111:
112:  int main()
113:  {
114:      Dog fido;
115:      Dog rover(5);
116:      Dog buster(6,8);
117:      Dog yorkie (3,YORKIE);
118:      Dog dobbie (4,20,DOBERMAN);
119:      fido.Speak();
120:      rover.WagTail();
121:      std::cout << "Yorkie is "
122:          << yorkie.GetAge() << " years old
";
123:      std::cout << "Dobbie weighs "
124:          << dobbie.GetWeight() << " pounds
";
125:      return 0;
126:  }

The output has been numbered so that each line can be referred to in the analysis. These numbers do not print in the actual output.



1:  Mammal constructor...
2:  Dog constructor...
3:  Mammal(int) constructor...
4:  Dog(int) constructor...
5:  Mammal(int) constructor...
6:  Dog(int, int) constructor...
7:  Mammal(int) constructor...
8:  Dog(int, BREED) constructor....
9:  Mammal(int) constructor...
10: Dog(int, int, BREED) constructor...
11: Mammal sound!
12: Tail wagging...
13: Yorkie is 3 years old.
14: Dobie weighs 20 pounds.
15: Dog destructor. . .
16: Mammal destructor...
17: Dog destructor...
18: Mammal destructor...
19: Dog destructor...
20: Mammal destructor...
21: Dog destructor...
22: Mammal destructor...
23: Dog destructor...
24: Mammal destructor...
						

In Listing 16.4, Mammal's constructor has been overloaded on line 10 to take an integer, the Mammal's age. The implementation on lines 58–63 initializes itsAge with the value passed into the constructor, and itsWeight with the value 5.


Dog has overloaded five constructors on lines 32–36. The first is the default constructor. The second takes the age, which is the same parameter that the Mammal constructor takes. The third constructor takes both the age and the weight; the fourth takes the age and breed; and the fifth takes the age, weight, and breed.

Note that on line 71 Dog's default constructor calls Mammal's default constructor. Although it is not strictly necessary to do this, it serves as documentation that you intended to call the base constructor, which takes no parameters. The base constructor would be called in any case, but actually doing so makes your intentions explicit.

The implementation for the Dog constructor, which takes an integer, is on lines 77–82. In its initialization phase (lines 78–79), Dog initializes its base class, passing in the parameter; and then it initializes its breed.

Another Dog constructor is on lines 84–90. This one takes two parameters. Once again, it initializes its base class by calling the appropriate constructor, but this time it also assigns weight to its base class's variable itsWeight. Note that you cannot assign to the base class variable in the initialization phase. That is, you can not write

Dog::Dog(int age, int weight):
Mammal(age),
itsBreed(YORKIE),
itsWeight(weight)       // error!
{
    std::cout << "Dog(int, int) constructor...
";
}

because you are not allowed to initialize a value in the base class. Similarly, you may not write

Dog::Dog(int age, int weight):
Mammal(age, weight),    // error!
itsBreed(YORKIE)
{
    std::cout << "Dog(int, int) constructor...
";
}

because Mammal does not have a constructor that takes the weight parameter; you must do this assignment within the body of the Dog's constructor.

Dog::Dog(int age, int weight):
Mammal(age),        // base constructor
itsBreed(YORKIE)    // initialization
{
    itsWeight = weight;   // assignment

Walk through the remaining constructors to make sure you are comfortable with how they work. Note what is initialized and what must wait for the body of the constructor.

The output has been numbered so that each line can be referred to in this analysis. The first two lines of output represent the instantiation of Fido, using the default constructor.

In the output, lines 3 and 4 represent the creation of rover. Lines 5 and 6 represent buster. Note that the Mammal constructor that was called is the constructor that takes one integer, but the Dog constructor is the constructor that takes two integers.

After all the objects are created, they are used and then go out of scope. As each object is destroyed, first the Dog destructor and then the Mammal destructor is called; there are five of each in total.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.52.124