子类如何调用以不同方式初始化成员变量的父类的构造函数?[C++]

tuz*_*zer 1 c++ inheritance constructor

如何在其构造函数中计算子类的成员变量的值,然后传递给父的构造函数?

动机是,如果父类默认构造函数中有很多计算,那么我不想进行那些计算,只是将它们替换为子类后面计算的那些计算.

例如:

Car.h

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

};
Run Code Online (Sandbox Code Playgroud)

Car.cpp

Car::Car()
{
    //some other long computation 
    price = DetermineMarketPrice();
}
Car::Car(double Price)
{
    price = Price;
}
...
Run Code Online (Sandbox Code Playgroud)

Porche.h

class Porche : public Car
{
     public:
         Porche();
     ...   
     private:
         double price;
         double discount;
         double fee;
         double DetermineMarketPrice();
         double RetrieveFee();
         double CheckDiscount();
         ...
};
Run Code Online (Sandbox Code Playgroud)

Porche.cpp

Porche::Porche():Car(price)
{
     discount = CheckDiscount();
     fee = = RetrieveFee(); 
     price = DetermineMarketPrice() * (1-discount) + fee; 
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,保时捷的价格尚不得而知.它必须在构造函数中计算.如果我像这样调用父的构造函数,似乎它只会传递尚未初始化的价格.

传递一些只能在Child类初始化结束时知道的成员变量值的好方法是什么?

And*_*ejJ 5

你不能这样做,基类构造函数首先按照初始化顺序执行,在数据成员初始化之前和派生类构造函数的主体执行之前。如果这些是代价高昂的计算,最好的办法可能是将它们移出构造函数。

编辑:从技术上讲,有一种方法可以解决此问题,方法是创建第二个构造函数,或者使用具有默认参数值的默认构造函数,该构造函数可用于停止基类中的计算,如下所示:

struct SkipCalculatePrice {};

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

class Ferrari: public Car {
public:
    Ferrari(): Car(SkipCaluclatePrice()) [...]
[...]
Run Code Online (Sandbox Code Playgroud)

但是,我个人不建议将此作为一种良好的设计实践。据了解,人们希望避免延迟初始化作为一种​​反模式,但是,对于昂贵的计算,正确完成延迟初始化可能是正确的答案:

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

class Ferrari: public Car {
    double calculatePrice();
};
Run Code Online (Sandbox Code Playgroud)


Jam*_*nze 5

很大程度上取决于实际情况,但一个常见的解决方案是将所有计算卸载到静态成员中,因此您可以编写:

Porsche::Porsche()
    : Car( calclulatePrice() )
{
    //  ...
}
Run Code Online (Sandbox Code Playgroud)

如果(在您的示例中建议)您首先必须在基类中设置变量之前计算其他成员变量,这将不起作用.对于像你提出的那样的情况,最简单的解决方案是用0初始化基类,然后稍后设置实际值.

更一般地说,我不得不怀疑你的设计.基类和派生类都有成员是不对的price.在最常使用的继承中,基类将是抽象的,没有数据成员.但即使不是这种情况,基类的数据成员也不会在派生类中重复:如果派生类可以以任意方式设置或更改它们,则它们可能受到保护; 否则,它们位于基类中,并且只能由基类中的函数操作(可以从派生类调用).