Constructors in Derived Classes

As we explained in the preceding section, instantiating a derived class object begins a chain of constructor calls in which the derived class constructor, before performing its own tasks, invokes its direct base class's constructor either explicitly (via a constructor initializer with the base reference) or implicitly (calling the base class's default constructor or parameterless constructor). Similarly, if the base class is derived from another class (as every class except object is), the base class constructor invokes the constructor of the next class up in the hierarchy, and so on. The last constructor called in the chain is always the constructor for class object. The original derived class constructor's body finishes executing last. Each base class's constructor manipulates the base class instance variables that the derived class object inherits. For example, consider again the CommissionEmployee3BasePlusCommissionEmployee4 hierarchy from Fig. 10.13 and Fig. 10.14. When an application creates a BasePlusCommissionEmployee4 object, the BasePlusCommissionEmployee4 constructor is called. That constructor calls CommissionEmployee3's constructor, which in turn implicitly calls object's constructor. Class object's constructor has an empty body, so it immediately returns control to CommissionEmployee3's constructor, which then initializes the private instance variables of CommissionEmployee3 that are part of the BasePlusCommissionEmployee4 object. When CommissionEmployee3's constructor completes execution, it returns control to BasePlusCommissionEmployee4's constructor, which initializes the BasePlusCommissionEmployee4 object's baseSalary.

Software Engineering Observation 10 6

When an application creates a derived class object, the derived class constructor immediately calls the base class constructor (explicitly, via base, or implicitly). The base class constructor's body executes to initialize the base class's instance variables that are part of the derived class object, then the derived class constructor's body executes to initialize the derived class-only instance variables. Even if a constructor does not assign a value to an instance variable, the variable is still initialized to its default value (i.e., 0 for simple numeric types, false for bools and null for references).

Our next example revisits the commission employee hierarchy by declaring a CommissionEmployee4 class (Fig. 10.16) and a BasePlusCommissionEmployee5 class (Fig. 10.17). Each class's constructor prints a message when invoked, enabling us to observe the order in which the constructors in the hierarchy execute.

Figure 10.16. CommissionEmployee4 class represents a commission employee.

(This item is displayed on pages 495 - 496 in the print version)

1 // Fig. 10.16: CommissionEmployee4.cs 2 // CommissionEmployee4 class represents a commission employee. 3 using System; 4 5 public class CommissionEmployee4 6 { 7 private string firstName; 8 private string lastName; 9 private string socialSecurityNumber; 10 private decimal grossSales; // gross weekly sales 11 private decimal commissionRate; // commission percentage 12 13 // five-parameter constructor 14 public CommissionEmployee4( string first, string last, string ssn, 15 decimal sales, decimal rate ) 16 { 17 // implicit call to object constructor occurs here 18 firstName = first; 19 lastName = last; 20 socialSecurityNumber = ssn; 21 GrossSales = sales; // validate gross sales via property 22 CommissionRate = rate; // validate commission rate via property 23 24 Console.WriteLine( " CommissionEmployee4 constructor: " + this ); 25 } // end five-parameter CommissionEmployee4 constructor 26 27 // read-only property that gets commission employee's first name 28 public string FirstName 29 { 30 get 31 { 32 return firstName; 33 } // end get 34 } // end property FirstName 35 36 // read-only property that gets commission employee's last name 37 public string LastName 38 { 39 get 40 { 41 return lastName; 42 } // end get 43 } // end property LastName 44 45 // read-only property that gets 46 // commission employee's social security number 47 public string SocialSecurityNumber 48 { 49 get 50 { 51 return socialSecurityNumber; 52 } // end get 53 } // end property SocialSecurityNumber 54 55 // property that gets and sets commission employee's gross sales 56 public decimal GrossSales 57 { 58 get 59 { 60 return grossSales; 61 } // end get 62 set 63 { 64 grossSales = ( value < 0 ) ? 0 : value; 65 } // end set 66 } // end property GrossSales 67 68 // property that gets and sets commission employee's commission rate 69 public decimal CommissionRate 70 { 71 get 72 { 73 return commissionRate; 74 } // end get 75 set 76 { 77 commissionRate = ( value > 0 && value < 1 ) ? value : 0; 78 } // end set 79 } // end property CommissionRate 80 81 // calculate commission employee's pay 82 public virtual decimal Earnings() 83 { 84 return CommissionRate * GrossSales; 85 } // end method Earnings 86 87 // return string representation of CommissionEmployee object 88 public override string ToString() 89 { 90 return string.Format( 91 "{0}: {1} {2} {3}: {4} {5}: {6:C} {7}: {8:F2}", 92 "commission employee", FirstName, LastName, 93 "social security number", SocialSecurityNumber, 94 "gross sales", GrossSales, "commission rate", CommissionRate ); 95 } // end method ToString 96 } // end class CommissionEmployee4

Figure 10.17. BasePlusCommissionEmployee5 class declaration.

(This item is displayed on pages 497 - 498 in the print version)

1 // Fig. 10.17: BasePlusCommissionEmployee5.cs 2 // BasePlusCommissionEmployee5 class declaration. 3 using System; 4 5 public class BasePlusCommissionEmployee5 : CommissionEmployee4 6 { 7 private decimal baseSalary; // base salary per week 8 9 // six-parameter derived class constructor 10 // with call to base class CommissionEmployee4 constructor 11 public BasePlusCommissionEmployee5( string first, string last, 12 string ssn, decimal sales, decimal rate, decimal salary ) 13 : base( first, last, ssn, sales, rate ) 14 { 15 BaseSalary = salary; // validate base salary via property 16 17 Console.WriteLine( 18 " BasePlusCommissionEmployee5 constructor: " + this ); 19 } // end six-parameter BasePlusCommissionEmployee5 constructor 20 21 // property that gets and sets 22 // base-salaried commission employee's base salary 23 public decimal BaseSalary 24 { 25 get 26 { 27 return baseSalary; 28 } // end get 29 set 30 { 31 baseSalary = ( value < 0 ) ? 0 : value; 32 } // end set 33 } // end property BaseSalary 34 35 // calculate earnings 36 public override decimal Earnings() 37 { 38 return BaseSalary + base.Earnings(); 39 } // end method Earnings 40 41 // return string representation of BasePlusCommissionEmployee5 42 public override string ToString() 43 { 44 return string.Format( "{0} {1} {2}: {3:C}", 45 "base-salaried", base.ToString(), "base salary", BaseSalary ); 46 } // end method ToString 47 } // end class BasePlusCommissionEmployee5

Class CommissionEmployee4 (Fig. 10.16) contains the same features as the version of the class shown in Fig. 10.13. We modified the constructor (lines 1425) to output text when it is invoked. Note that concatenating this with a string literal (line 24) implicitly invokes the ToString method of the object being constructed to obtain the object's string representation.

Class BasePlusCommissionEmployee5 (Fig. 10.17) is almost identical to BasePlusCommissionEmployee4 (Fig. 10.14), except that BasePlusCommissionEmployee5's constructor outputs text when invoked. As in CommissionEmployee4 (Fig. 10.16), we concatenate this with a string literal to implicitly obtain the object's string representation.

Figure 10.18 demonstrates the order in which constructors are called for objects of classes that are part of an inheritance hierarchy. Method Main begins by instantiating CommissionEmployee4 object employee1 (lines 1011). Next, lines 1416 instantiate BasePlusCommissionEmployee5 object employee2. This invokes the CommissionEmployee4 constructor, which prints output with the values passed from the BasePlusCommissionEmployee5 constructor, then performs the output specified in the BasePlusCommissionEmployee5 constructor. Lines 1921 then instantiate BasePlusCommissionEmployee5 object employee3. Again, the CommissionEmployee4 and BasePlusCommissionEmployee5 constructors are both called. In each case, the body of the CommissionEmployee4 constructor executes before the body of the BasePlusCommissionEmployee5 constructor. Note that employee2 is constructed completely before construction of employee3 begins.

Figure 10.18. Display order in which base class and derived class constructors are called.

(This item is displayed on pages 498 - 499 in the print version)

1 // Fig. 10.18: ConstructorTest.cs 2 // Display order in which base class and derived class constructors 3 // are called. 4 using System; 5 6 public class ConstructorTest 7 { 8 public static void Main( string[] args ) 9 { 10 CommissionEmployee4 employee1 = new CommissionEmployee4( "Bob", 11 "Lewis", "333-33-3333", 5000.00M, .04M ); 12 13 Console.WriteLine(); 14 BasePlusCommissionEmployee5 employee2 = 15 new BasePlusCommissionEmployee5( "Lisa", "Jones", 16 "555-55-5555", 2000.00M, .06M, 800.00M ); 17 18 Console.WriteLine(); 19 BasePlusCommissionEmployee5 employee3 = 20 new BasePlusCommissionEmployee5( "Mark", "Sands", 21 "888-88-8888", 8000.00M, .15M, 2000.00M ); 22 } // end Main 23 } // end class ConstructorTest  

CommissionEmployee4 constructor: commission employee: Bob Lewis social security number: 333-33-3333 gross sales: $5,000.00 commission rate: 0.04 CommissionEmployee4 constructor: base-salaried commission employee: Lisa Jones social security number: 555-55-5555 gross sales: $2,000.00 commission rate: 0.06 base salary: $0.00 BasePlusCommissionEmployee5 constructor: base-salaried commission employee: Lisa Jones social security number: 555-55-5555 gross sales: $2,000.00 commission rate: 0.06 base salary: $800.00 CommissionEmployee4 constructor: base-salaried commission employee: Mark Sands social security number: 888-88-8888 gross sales: $8,000.00 commission rate: 0.15 base salary: $0.00 BasePlusCommissionEmployee5 constructor: base-salaried commission employee: Mark Sands social security number: 888-88-8888 gross sales: $8,000.00 commission rate: 0.15 base salary: $2,000.00

Software Engineering with Inheritance

Категории