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

C++ 子类如何调用初始化成员变量的父类的构造函数?[C+;+;],c++,inheritance,constructor,C++,Inheritance,Constructor,如何在子类的构造函数中计算其成员变量的值,然后传递给父类的构造函数 这样做的动机是,如果父类默认构造函数中有大量计算,那么我不想做这些计算,只想让子类立即将它们替换为子类计算的结果 例如: 汽车 Car.cpp Car::Car() { //some other long computation price = DetermineMarketPrice(); } Car::Car(double Price) { price = Price; } ... 门廊 clas

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

这样做的动机是,如果父类默认构造函数中有大量计算,那么我不想做这些计算,只想让子类立即将它们替换为子类计算的结果

例如:

汽车

Car.cpp

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

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

Porche::Porche():Car(price)
{
     discount = CheckDiscount();
     fee = = RetrieveFee(); 
     price = DetermineMarketPrice() * (1-discount) + fee; 
}
在这种情况下,门廊的价格还不得而知。它必须在构造函数中计算。如果我像这样调用父级的构造函数,它似乎只传递尚未初始化的价格


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

只需将计算代码从构造函数中移到实用函数中,如
CalculatePrice()
。构造对象,然后调用此函数。

在父对象的构造函数中使用虚方法来确定价格。在每个子类中重新定义此方法

您不能这样做,基类构造函数首先按照初始化顺序执行,然后是数据成员初始化,然后是派生类构造函数的主体执行。如果这些计算成本很高,那么最好将它们移出构造函数

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

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

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

Porsche::Porsche()
    : Car( calclulatePrice() )
{
    //  ...
}
如果(如你的例子所示)你首先必须这样做,那么这是行不通的 在中设置变量之前,计算其他成员变量 基类。对于您所介绍的情况,最简单的解决方案 就是用0初始化基类,然后设置实际的 以后再估价

一般来说,我想知道你的设计。这不可能是对的 基类和派生类都有一个成员
price
。 在最常用的继承中,基类将是 抽象,没有数据成员。但即使情况并非如此 基类的数据成员在派生类中不重复 类:如果派生类可以以任意方式设置或更改它们 这样,他们就可以得到保护;否则,它们在基类中,并且 仅由基类中的函数操作(可以调用
在构造函数中调用虚方法不会像这样工作,因为调用该方法时还没有创建子对象。这不起作用,从构造函数调用虚函数时,将调用基类的函数,不是派生的。为什么要将昂贵的计算移出构造函数?@fdlm:详细讨论了这个问题。在这种情况下,这个问题有一个实用的和哲学的答案。从实用的角度来看,基构造函数被称为派生类构造的第一阶段,因此在那里进行既昂贵又不必要的计算是浪费的。从哲学设计的角度来看,Car类代表了什么使一辆车成为一辆车,构造器设置了所有车都通用的东西。如果法拉利是一辆汽车,而按汽车类别计算的价格不适用于法拉利,那么这不是所有汽车的共同点。我明白你的意思。Car的构造函数(父类)实际上应该只对Car的所有类型(子类)通用的东西进行初始化。但在这种情况下,既然价格必须计算出来,那么把它放在构造函数中是否合乎逻辑呢?否则,程序员在声明Car对象时需要记住做两件事。如果我想将对象用作其他函数的参数,它将不起作用。请注意第二个延迟计算示例:程序员不必记住计算价格,它将在程序首次尝试访问价格时计算。您能确定MarkedPrice,RetrieveFee和CheckDiscount static?除此之外,
double
不适合花钱。
lots\u of pennies*0.01
的值不一定等于
lots\u of pennies/100
。感谢您的评论和建议!现在我意识到,与其把它当作一个技术问题来处理,不如把它当作一个设计问题来处理。尽管有办法解决这个问题,但我认为派生类应该只是具有附加规范或函数的父类。继承并不意味着将做不同事情的两个类视为一个类。我想我要做的是创建另一个更通用的类,作为这两个类的父类。但是,我知道每次“制造”一辆车时,我都需要计算价格。如果程序员在创建对象之后忘记使用CalculatePrice()函数,那么价格将不会初始化,并可能导致其他一些错误。这就是为什么我试图在构造函数中完成所有工作,因为它无论如何都必须完成。在这种情况下,创建一个工厂,该工厂同时构造车辆并调用计算函数。
price
变量可以被保护或管理
Porsche::Porsche()
    : Car( calclulatePrice() )
{
    //  ...
}