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类初始化结束时知道的成员变量值的好方法是什么?
你不能这样做,基类构造函数首先按照初始化顺序执行,在数据成员初始化之前和派生类构造函数的主体执行之前。如果这些是代价高昂的计算,最好的办法可能是将它们移出构造函数。
编辑:从技术上讲,有一种方法可以解决此问题,方法是创建第二个构造函数,或者使用具有默认参数值的默认构造函数,该构造函数可用于停止基类中的计算,如下所示:
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)
很大程度上取决于实际情况,但一个常见的解决方案是将所有计算卸载到静态成员中,因此您可以编写:
Porsche::Porsche()
: Car( calclulatePrice() )
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
如果(在您的示例中建议)您首先必须在基类中设置变量之前计算其他成员变量,这将不起作用.对于像你提出的那样的情况,最简单的解决方案是用0初始化基类,然后稍后设置实际值.
更一般地说,我不得不怀疑你的设计.基类和派生类都有成员是不对的price
.在最常使用的继承中,基类将是抽象的,没有数据成员.但即使不是这种情况,基类的数据成员也不会在派生类中重复:如果派生类可以以任意方式设置或更改它们,则它们可能受到保护; 否则,它们位于基类中,并且只能由基类中的函数操作(可以从派生类调用).
归档时间: |
|
查看次数: |
16563 次 |
最近记录: |