所以,我写了下面的代码。
#include <iostream>
class AbstractMachine
{
public:
void powerOn();
void powerOff();
bool isPoweredOn();
virtual ~AbstractMachine();
protected:
virtual void powerOnImpl() = 0;
virtual void powerOffImpl() = 0;
private:
bool m_isPoweredOn;
};
bool AbstractMachine::isPoweredOn()
{
return m_isPoweredOn;
}
void AbstractMachine::powerOn()
{
if (!m_isPoweredOn)
{
powerOnImpl();
m_isPoweredOn = true;
}
}
void AbstractMachine::powerOff()
{
if (m_isPoweredOn)
{
powerOffImpl();
m_isPoweredOn = false;
}
}
AbstractMachine::~AbstractMachine()
{
powerOff(); // (1)
std::cout << "Destroying a machine" << std::endl;
}
class AirConditioner : public AbstractMachine
{
protected:
void powerOnImpl() override;
void powerOffImpl() override;
public:
~AirConditioner();
};
void AirConditioner::powerOnImpl()
{
std::cout << "Turning on air conditioner" << std::endl;
}
void AirConditioner::powerOffImpl()
{
std::cout << "Turning off air conditioner" << std::endl;
}
AirConditioner::~AirConditioner()
{
//powerOff(); // (2)
std::cout << "Destroing air conditioner" << std::endl;
}
int main()
{
AbstractMachine *machine = new AirConditioner();
machine->powerOn();
delete machine;
}
这将失败,因为当基础析构函数调用(1)上的派生函数时,派生对象已被销毁。
这在我评论(1)和取消注释(2)时运行正常,但我想要做的是自动并且在它被销毁之前总是关闭机器,尽管'断电'动作取决于自定义机器。
有没有更好的方法呢?我应该放弃吗?或者它甚至不是OOP设计的正确方法?
正如您所观察到的,当基类构造函数运行时,派生类部分不再存在。没有诀窍可以做到这一点,所以没有办法在基础析构函数中完成所有操作。
你只需要确定关闭的哪个部分属于每个级别,并让每个析构函数都处理它自己的级别。当对象被销毁时,每个级别的析构函数都是从下到上运行,所以一切都完成了。我认为这将是OOP方法。
几点意见:
AbstractMachine
不知道在powerOffImpl()
中将执行什么逻辑,程序员不能确定派生类不会抛出异常,并且析构函数应该总是避免抛出异常。更好的是AirConditioner
直接在析构函数中调用powerOffImpl()
,然后AirConditioner
的实现者知道任何异常风险,并且可以编写代码来缓解这种情况。如果执行此操作没有意义,实现者也可以选择不调用powerOffImpl()
。IMachine
)继承通常更好,以便具体类可以为自己做出这些决定,这也避免了虚方法问题。powerOffImpl()
?考虑它的另一种方法是考虑机器的寿命可能与开关寿命不同。它们是不同的东西,所以也许它们应该以不同的方式建模。在这种情况下,我会考虑使用单独的MachineSession
对象来模拟开关生命周期。 MachineSession
构造函数接受IMachine
的一个实例并执行IMachine.powerOn()
,并在其析构函数中调用IMachine.powerOff()
(假设powerOff给出noexcept保证,或者用try
/ catch
保护它)。这也避免了对m_isPoweredOn
的需要,因为如果你有一个有效的MachineSession
,那么你知道机器已通电。