2

How can I compute the value of a child class's member variable in it's constructor, and then pass on to the parent's constructor??

The motivation is that, if there's a lot of calculation in the parent class default constructor, then I don't want to have to do those calculation and only have them replaced by those computed by child class right after.

For example:

Car.h

class Car 
{  
 public:
    Car();
    Car(double Price) ;
    ...
 private:
    double price;
    double DetermineMarketPrice();

};

Car.cpp

Car::Car()
{
    //some other long computation 
    price = DetermineMarketPrice();
}
Car::Car(double Price)
{
    price = Price;
}
...

Porche.h

class Porche : public Car
{
     public:
         Porche();
     ...   
     private:
         double price;
         double discount;
         double fee;
         double DetermineMarketPrice();
         double RetrieveFee();
         double CheckDiscount();
         ...
};

Porche.cpp

Porche::Porche():Car(price)
{
     discount = CheckDiscount();
     fee = = RetrieveFee(); 
     price = DetermineMarketPrice() * (1-discount) + fee; 
}

In this case, the price of a Porche isn't known yet. It has to be calculated in the constructor. If I call the parent's constructor like this, seems like it would only pass the not-yet-initialized price.

What would be a good way to pass some value of member variables that can only be known at the end of the Child class initialization???

shift66
  • 11,760
  • 13
  • 50
  • 83
tuzzer
  • 1,119
  • 3
  • 12
  • 20
  • Can you make DetermineMarkedPrice, RetrieveFee and CheckDiscout static? – fdlm Feb 17 '12 at 09:07
  • Quite aside from anything else, `double` is not a suitable type for money. The value of `lots_of_pennies * 0.01` is not necessarily equal to `lots_of_pennies / 100`. – Steve Jessop Feb 17 '12 at 10:05
  • Thanks for all your comments and advice! Now I realized that rather than treating this as a technical problem as in how to code it, I should treat this more as a design problem. Although there are ways to work around it, I think derived classes should simply be the parent class with additional specifications or functions. Inheritance is not meant to treat two classes doing different things as one class. I guess what I would do is to create another more general class that will serve as the parent for both of those classes. – tuzzer Feb 21 '12 at 00:12

4 Answers4

5

You can't do that, the base class constructors are executed first in the initialisation order, before data members are initialised and before the derived class constructor's body is executed. If these are costly calculations, the best thing to do may be moving them out of the constructor.

EDIT: There's technically a way to work around this problem, by creating a second constructor, or having a default constructor with a default parameter value, which can be used to stop the calculations in the base class, like so:

struct SkipCalculatePrice {};

class Car {
public:
    Car();
protected:
    Car(SkipCalculatePrice);
};

class Ferrari: public Car {
public:
    Ferrari(): Car(SkipCaluclatePrice()) [...]
[...]

However, I personally would not recommend this as a good design practice. It is understood that one would want to avoid delayed initialization as an anti-pattern, however, for costly calculations, properly done lazy initailization might be the right answer:

class Car {
    virtual double calculatePrice();
    bool priceCalculated;
    double price;
public:
    double getPrice() {
        if(!priceCaluclated) {
            price = calculatePrice();
        }
        return price;
    }
}

class Ferrari: public Car {
    double calculatePrice();
};
AndrzejJ
  • 720
  • 5
  • 11
  • Why should costly calculations be moved out of the constructor? – fdlm Feb 17 '12 at 09:06
  • @fdlm: [This question](http://stackoverflow.com/questions/293967/) discusses this issue in full length. – Björn Pollex Feb 17 '12 at 09:22
  • In this case there's both a pragmatical and a philosophical answer to the question. From a pragmatical viewpoint, the base constructor is called as the first stage of the derived class construction, so making the calculations there, which are both costly and unnecessary, is wasteful. From a philosophical design POV, the Car class represents what makes a car a car, and the constructor sets up stuff that's common to all cars. If the Ferrari is a car, and the price, as calculated by the Car class, does not apply to the Ferrari, then it's not something that's common to all cars – AndrzejJ Feb 17 '12 at 10:51
  • I understand what you mean. The constructor of Car (the parent class) should really only do the initialization for things common to all kinds (child classes) of car. But then in this case, since price must be calculated, won't it be logical to put it in the constructor? Otherwise, the programmer needs to remember to do two things when he or she declares a Car object. And it won't work if I want to use the object as an argument of some other functions. – tuzzer Feb 20 '12 at 05:24
  • Note the second example with lazy calculation: the programmer doesn't have to remember to calculate the price, it will be calculated when the program tries to access the price for the first time. – AndrzejJ Feb 21 '12 at 14:44
  • Obviously lazy calculation may not be appropriate in some cases, e.g. where responsiveness is important - we may really want to do all lengthy calculations up front so there's no pause when a user or service requests to know the price. However, you cannot in any case solve this by calling a virtual function from the constructor. You may use the workaround with `SkipCalculatePrice` type; if you want to make it less ugly and more flexible, you may define something like `CarConstructorParams` struct, which can contain a number of flags for different base fields. – AndrzejJ Feb 21 '12 at 14:51
5

A lot depends on the actual situation, but one frequent solution is to offload all of the calculations into a static member, so you can write:

Porsche::Porsche()
    : Car( calclulatePrice() )
{
    //  ...
}

This won't work if (as your example suggests) you first have to calculate other member variables, before setting the variable in the base class. For cases like the one you present, the simplest solution is just to initialize the base class with 0, and then set the actual value later.

More generally, I have to wonder about your design. It can't be right that both the base class and the derived class have a member price. In the most frequent use of inheritance, the base class will be abstract, with no data members. But even when this is not the case, the data members of the base class are not duplicated in the derived classes: if the derived classes can set or change them in an arbitrary way, they may be protected; otherwise, they are in the base class, and only manipulated by functions in the base class (which may be called from the derived class).

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • The `price` variable could be protected or be manipulable by functions in the base class. Say `CalculatePrice()` cannot be static. It is probably better if it is not called in the constructor. But since I know that `CalculatePrice()` must be performed, I thought that it would be appropriate to call that function in the constructor. However, since the way to calculate price is different for the child class, I don't want to use the the base class's constructor to use the implementation of the base class's `CalculatePrice()`. Instead, the constructor should use the Child class version. – tuzzer Feb 20 '12 at 05:40
  • If says I overloaded the 'CalculatePrice()' in the Porche (child) class, when the constructor of the Car (parent) class calls the `CalculatePrice()`, I believe that it would call the Car's one. – tuzzer Feb 20 '12 at 05:43
  • I guess the best way to do it would be to have the Child class calls another constructor of the base class that doesn't do those costly calculation. – tuzzer Feb 20 '12 at 05:48
  • @tuzzer During construction of the base class, the object type is base, and all virtual function calls will resolve to the base class. There are several ways to work around this: one obvious one is to use the strategy pattern, to delegate the calculations to an already constructed strategy class. – James Kanze Feb 20 '12 at 08:36
1

Just move the calculation code out of the constructor to a utility function such as CalculatePrice( ). Construct the object and then call this function.

Nick
  • 25,026
  • 7
  • 51
  • 83
  • But then, I know that I will need to calculate price every single time I "make" a car. If the programmer forgot to use the CalculatePrice() function right after creating the object, then the price will not be initialized and might result in some other errors. That's why I tried to have everything done at the constructor, since it has to be done anyways. – tuzzer Feb 20 '12 at 05:17
  • In that case, create a factory which both constructs the vehicles and calls the calculate function. – Nick Feb 20 '12 at 08:25
-1

Use an virtual method in the constructor of the parent to determine the price. Redefine this method in each child class.

UmNyobe
  • 22,539
  • 9
  • 61
  • 90
  • Calling a virtual method in a constructor won't work like that, because the child-object will not yet have been created when that method is called. – Björn Pollex Feb 17 '12 at 09:02
  • This won't work, when you call a virtual function from the constructor, the base class's function will be called, not the derived one's. – AndrzejJ Feb 17 '12 at 09:03