tuzzer
tuzzer

Reputation: 1149

How can a child class call the constructor of the parent class that initializes member variables differently? [C++]

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???

Upvotes: 2

Views: 19501

Answers (4)

AndrzejJ
AndrzejJ

Reputation: 740

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();
};

Upvotes: 5

Nick
Nick

Reputation: 25799

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

Upvotes: 1

James Kanze
James Kanze

Reputation: 153909

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).

Upvotes: 5

UmNyobe
UmNyobe

Reputation: 22890

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

Upvotes: -1

Related Questions