Как дочерний класс может вызвать конструктор родительского класса, который по-разному инициализирует переменные-члены? [C ++] - PullRequest
1 голос
/ 17 февраля 2012

Как я могу вычислить значение переменной члена дочернего класса в его конструкторе, а затем передать конструктору родителя ??

Мотивация заключается в том, что, если в конструкторе по умолчанию родительского класса много вычислений, мне не нужно выполнять эти вычисления, а заменять их только теми, которые вычисляются дочерним классом сразу после.

Например:

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

В этом случае цена Порше еще не известна. Это должно быть рассчитано в конструкторе. Если бы я назвал конструктор родителя таким образом, кажется, что он пройдет только еще не инициализированную цену.

Что может быть хорошим способом передачи некоторого значения переменных-членов, которые могут быть известны только в конце инициализации класса Child ???

Ответы [ 4 ]

5 голосов
/ 17 февраля 2012

Многое зависит от реальной ситуации, но одним из частых решений является Перенесите все вычисления в статический член, так что вы можете написать:

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

Это не сработает, если (как показывает ваш пример) вы сначала должны вычислить другие переменные-члены, прежде чем устанавливать переменную в Базовый класс. Для таких случаев, как тот, который вы представляете, самое простое решение просто инициализировать базовый класс с 0, а затем установить фактический ценность позже.

В общем, мне нужно задуматься о вашем дизайне. Это не может быть правильно что и базовый класс, и производный класс имеют член price. При наиболее частом использовании наследования базовый класс будет абстрактный, без данных членов. Но даже если это не так, члены данных базового класса не дублируются в производных классы: если производные классы могут устанавливать или изменять их произвольно Кстати, они могут быть защищены; в противном случае они находятся в базовом классе, и манипулировать только функциями в базовом классе (который может быть вызван из производного класса).

4 голосов
/ 17 февраля 2012

Вы не можете этого сделать, конструкторы базового класса выполняются первыми в порядке инициализации, до инициализации членов данных и до выполнения тела конструктора производного класса. Если это дорогостоящие вычисления, лучшее, что можно сделать, это удалить их из конструктора.

РЕДАКТИРОВАТЬ: Технически есть способ обойти эту проблему, создав второй конструктор или имея конструктор по умолчанию со значением параметра по умолчанию, который можно использовать для остановки вычислений в базовом классе, например:

struct SkipCalculatePrice {};

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

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

Однако я лично не рекомендовал бы это как хорошую практику проектирования. Понятно, что желательно избегать отложенной инициализации как антишаблона, однако для дорогостоящих вычислений правильная ленивая инициализация может быть правильным ответом:

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

class Ferrari: public Car {
    double calculatePrice();
};
1 голос
/ 17 февраля 2012

Просто переместите код вычисления из конструктора в служебную функцию, например CalculatePrice( ).Построить объект и затем вызвать эту функцию.

0 голосов
/ 17 февраля 2012

Используйте виртуальный метод в конструкторе родительского объекта для определения цены.Переопределите этот метод в каждом дочернем классе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...