c++ - 当继承只为某些最终类型引入先决条件时如何记录/断言

标签 c++ inheritance doxygen design-by-contract preconditions

考虑这个简单的基类 Foo 有一个函数 foo 调用一个纯虚函数 foo_,用 Doxygen 记录:

class Foo
{
  public:
    /** \brief This function logs x and does the job */
    void foo(double x);
  protected:
    /** \brief This function does the job */
    virtual void foo_(double x) = 0;
};

void Foo::foo(double x)
{
  std::clog << "'Foo::foo(double x)' is called with x = " << x << std::endl;
  this->foo_(x);
}

我没有先决条件来记录这个抽象类。

现在,考虑一个派生类 Bar,其上存在正确工作的先决条件:

class Bar : public Foo
{
  public:
    /**
     * \brief This function does the job
     * \pre   x must be greater or equal to 0
     */
    virtual void foo_(double x);
};

void Bar::foo_(double x)
{
  assert(x >= 0.0 && "PRE: x can't be negative");
  // Do the job
}

现在,当我调用由 foo 调用的 foo_ 时,我在 x 上有一个前提条件。然后,根据最终类型,我在 foo 上有一个先决条件。

一些问题:

  1. 我是否应该在 Foo::foo 中添加前置条件而不考虑最终类型?如果用户在使用该类时永远不知道最终类型,这看起来是合乎逻辑的。但是用户也可以有另一个类 BazFoo 派生,没有任何前提条件,并显式调用 Baz::foo(double) 负值.这应该不是问题。
  2. 在我的多态性概念中,Foo 类不必知道关于他的 child 的任何信息,那么前置条件就不会存在。但是母类的用户不必认识 child 就可以使用该类。如何解决这个矛盾?
  3. 是否有特定的(/最好的)方法来使用 Doxygen 记录此类事情?

最佳答案

在存在继承的情况下使用合约的一般规则是:

  1. 先决条件在后代中只会变得更弱。
  2. 后置条件只会在后代中变得更强。

这保证了祖先类的客户不受后代提供的任何实现的影响,因为这个客户不需要知道这样的后代的存在,它应该能够自由访问祖先类中声明的成员即使在运行时相应的表达式动态绑定(bind)到后代类的对象。

这在大多数情况下都能正常工作。但是在你的例子中,祖先类有一个先决条件 true 而后代类有一个更强的先决条件。有几种方法可以解决这个问题:

  1. 将更强的先决条件提升到祖先类。即使那里的实现处理了所有可能的情况,某些场景可能需要一个不平凡的先决条件,而客户必须处理它。
  2. 更改后代类的实现,使其处理所有情况并完全删除更强的前提条件。
  3. 通过向祖先类添加具有强前提条件的新方法或在后代类中使用不同的方法,避免重新声明有问题的成员,使其与原始方法无关。
  4. 使用抽象契约。它可以是对祖先类中定义的虚函数的调用,而不是直接指定契约。在您的示例中,该函数将返回 true。后代类可以重新定义这个函数并添加它需要的检查。此解决方案的主要缺点是客户端在调用方法之前必须检查抽象前提条件以确保它没有违反它。

最终决定取决于具体场景。

关于c++ - 当继承只为某些最终类型引入先决条件时如何记录/断言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37677782/

相关文章:

c++ - 加载时动态链接库调度

c++ - 交互类 - 组织代码

c# - 运行 epstopdf 时出现问题。检查你的 TeX 安装

git - 将 git 与 Doxygen FILE_VERSION_FILTER 结合使用

arduino - 用于 *.ino 文件的 Doxygen (Arduino)

c++ - 您最喜欢用 C/C++ 访问多个不同数据库(MySQL、Oracle...)的跨平台解决方案是什么?

c++ - 在运行时调整 char[] 的大小

c++ - Nuget 上可以使用 C++ 的 protobuf 吗?

c++ - 基类构造函数对派生类 C++ 不可见

python - module.__init__() takes at most 2 arguments 错误在Python