考虑下面的抽象类,它将作为一个类的接口,该类将某些对象所携带的信息写入标准输出。

class FileBuilder
{
public:
    virtual void build(const Object& object) = 0;

    virtual ~FileBuilder() = default;
};


此时,我将注意到Object也是具有派生类SpecialObject的抽象类。现在,我将如下实现SpecialFileBuilder : FileBuilder

class SpecialFileBuilder : public FileBuilder
{
public:
    void build(const SpecialObject& specialObject);
};

...

void SpecialFileBuilder::build(const SpecialObject& specialObject)
{
    // Do some stuff
}


我不完全理解为什么这不可能。 SpecialFileBuilder尊重接口FileBuilder,并且期望FileBuilder的任何地方都可以改为SpecialFileBuilder。非常感谢您的帮助。

当然,如果我将内容更改为以下内容,则可以使用。

void SpecialFileBuilder::build(const Object& object)


但是,在实现SpecialFileBuilder::build()的过程中,我需要使用以下事实:参数是SpecialObject,而不仅仅是Object

我应该如何进行这种设计?

最佳答案

TL; DR不,这没有任何意义。

完整版本如下。


  我不完全理解为什么这不可能。


virtual void build(const Object& object) = 0;


这个声明是一个承诺。它保证build可以接受任何Object作为参数。此类承诺对派生类具有法律约束力,即它们必须按照基类的规定执行承诺。请注意,声明并不保证build可以接受某些对象,而不能接受其他对象。

FileBuilder* builder = GetBuilder(); // we don't know what kind of builder it is

SpecialObject some;
builder->build(some); // must work

OtherSpecialObject some;
builder->build(other); // must work too

UnrelatedObject whatever;
builder->build(whatever); // must work as well


现在看另一个声明

void build(const SpecialObject& specialObject);


它违背了诺言。最初的承诺是坚定的。给我任何东西,我可以处理。新的承诺是微弱的。哦,我是一个特殊的小建造者,我只能应付特殊的小物件!

抱歉,您不能用一个较弱的承诺来取代一个较强的承诺。如果您被允许,我们将如何信任任何诺言?

现在,如果您的设计不符合该大纲,即您始终知道您会获得哪种类型的生成器,并且您不想承诺应对所有类型的对象,那么您为该工作选择了错误的工具。也许您想尝试一下通用编程。

template <typename T>
class FileBuilder {
   virtual void build (const T& t) = 0;
};

class SpecialBuilder:  public FileBuilder<SpecialObject> {
   void build (const SpecialObject& t) override;
};


现在上面的代码将无法正常工作,我们需要对其进行修复

FileBuilder<SpecialObject>* builder = GetBuilder<SpecialObject>(); // we know exactly what we want to build

SpecialObject some;
builder->build(some); // will work;

OtherSpecialObject other;
builder->build(other); // sorry that's not in the contract, won't compile

09-17 19:31
查看更多