使用隐式构造函数/显式转换运算符在C ++中按契约设计

时间:2013-12-19 16:25:38

标签: c++ design-by-contract

我最近读过有关按合同设计的内容,我想通过项目尝试使用它。当我尝试自己想出一些简单的解决方案时,我想到的第一件事就是这个:

#include <iostream>
using namespace std;

template <typename Type>
class Positive {
    Type value;

public:
    Positive(
        Type positive
    ) :
        value(positive)
    {
        if (!condition())
            errorAction();
    }

    Positive(
        const Positive& positive
    ) :
        value(positive.value)
        {} // no need to check since variable HAS to respect the contract

    Positive(
        const Positive&& positive
    ) :
        value(positive.value)
        {} // no need to check since variable HAS to respect the contract

    Positive& operator=(
        const Positive& positive
    ) {
        value = positive.value;
        return *this;
    }

    Positive& operator=(
        const Positive&& positive
    ) {
        value = positive.value;
        return *this;
    }

    operator Type() {
        return value;
    }

private:
    bool condition() {
        return value > 0;
    }

    void errorAction() {
        cout << "not positive value: " << value << endl;
        exit(-1);
    }
};

// contract: both inputs and output are positive
template <typename Type>
Positive<Type> minusPositive(
    Positive<Type> x,
    Positive<Type> y
) {
    return x - y;
}

int main() {
    int x = 10;
    int y = 20;
    int z = minusPositive<Type>(x, y);  // should fails since x-y <= 0

    cout << "Should never display this: " << z << endl;

    return 0;
}

它基本上使用隐式转换(构造函数)来启动负责检查契约的包装器和显式转换运算符以返回它。我认为它会很好用 - 参数会被自动包装和检查,而内部函数会自动解包内容。与返回参数类似。我喜欢这个想法,因为合约将在一个地方定义和检查(参数/返回值),方法体将没有额外的行。

但是我会讨论所有会发生的问题 - 我很可能不得不重载=运算符和可能的移动运算符,代码本身将非常灵活(每个合同都必须有自己独立的实现,我不确定模板是否有帮助),更不用说构造函数中的合同失败问题(我应该如何处理它?不检查其中的任何合同或当场终止程序?)。

我查了一些关于它的文章:

  • this one虽然我的if-not-throw-exception目前使用的可能更好依赖于宏,但我不确定我是否愿意这样做,
  • this approach看起来稍微好一些,但是从2005年开始,所以一些更好的做法可能会在此期间出现,
  • 最后that one看起来像第一个更复杂的版本,并在有关DbC的其他问题上被提及。

您是否知道任何方法/库可以产生干净,可读的代码,在定义每个新合同时不需要额外的大量工作?一些稳定和成熟的东西,最好是已经在Debian 7.3上可用而不编译大量的外部库,也没有添加几个新的存储库/ pinnings?

或者,您是否认为我最初提出的方法可以修复到实际有用的地步?

修改

要使这个问题不是一个偏离主题的话:使用与定义合同类似定义的类是否安全?会不会有一些陷阱,如果有的话,可以通过我使用这些课程或我实施它们的方式来避免吗?

0 个答案:

没有答案