有没有一种通用的方法来实现不变量
Is there a common way to implement invariants?
这是一个我想添加intvariations的基本示例,例如我的年龄不能低于0。
#include "InvariantTest.h"
#include <iostream>
#include <string>
using namespace std;
int age;
string name;
void setAge(int a) {
age = a;
}
void setName(string n) {
name = n;
}
string getNameandAge() {
string both;
both = name + to_string(age);
return both;
}
我找不到如何在c++中实现不变量的规范。
来自标签描述:
在计算机科学中,谓词被称为操作序列的不变量,条件是:如果谓词在序列开始前为真,那么在序列结束时为真。
例如,谓词是age > 0
。一系列操作是例如
setAge(42);
另一个
setAge(-123);
为了确保不违反不变量,您可以向setAge
:添加一个条件
void setAge(int a) {
if (a > 0) age = a;
}
这取决于您抛出异常、终止程序、采取任何其他操作,或者在指定值时忽略该值,这将违反不变量。不存在";"范数";,因为这取决于您想要采取什么操作,以及调用方可以从传递无效参数中得到什么。
你也可以使age
无符号,那么不变的age >= 0
总是成立的。
若要维护不变量,必须为所有可以修改受不变量影响的状态的函数建立一个后置条件。在您的示例中,不变量会影响全局变量。因此,后置条件将影响所有函数,因为所有函数都可能修改全局变量。这是个问题。
对状态的访问应限于负责维护不变量的一小部分函数。这通常被称为封装。一个面向对象的解决方案是将状态存储在类的私有成员中,从而限制对维护不变量的成员函数的访问。
至于函数如何维护应用于它们的post条件,函数的实现者必须非常勤奋,并确保函数返回后状态不会违反不变量。
在输入(即函数的参数)可能影响不变量的情况下,有许多不同的方法来维护不变量,有各种优点和缺点:
-
只需记录一个负数可能不会传递给
setAge
的预编码。如果调用方违反了该约定,那么由于随后违反了不变量,程序的行为可能是未定义的。这种方法可能是最快的,因为它不需要运行时检查。但是它是最容易出错的,因为它将检查转移给可能出错的调用者。
-
在这种特殊情况下,可以选择使用无符号整数类型来表示年龄。由于它不能表示负值,所以它作为隐式文档工作,调用方没有办法违反约定。
这种方法并不适用于所有类型,但在某些情况下可能非常高效和安全。
然而,在某些情况下,尤其是无符号整数,这可能是潜在的危险,因为程序员可能会做一些事情,比如减去两个年龄,其中数学结果是负的,但由于无符号算术而变成大的正值。在这种情况下,界面会很高兴,因为年龄满足先决条件,但行为可能与程序员所希望的不同。
-
在运行时检查输入,例如使用
if
语句。如果输入不好,有几种方法可以处理错误:- 引发异常
- 设置一些默认值,而不是给定的坏值。这可能是有问题的,因为状态与给定输入匹配的期望不成立
- 只需终止流程
- 将错误记录在文件中,并可能直接联系开发人员(例如通过电子邮件),但继续使用其他方法之一,如1。违反不变量或2。设置默认值、终止进程等
-
在编译时选择要使用上面哪种方法。这样做通常是为了在生产中使用更高的检查,但较慢的调试构建,较少的检查,较快的构建。这就是标准
assert
宏的作用。
所有这些方法都很常见,正确的选择取决于您的需求,并且在某种程度上是主观的。
通常,除了if (a > 0) age = a;
之外,您还需要至少添加一个调试断言assert(a > 0)
(这将在运行程序的调试构建时引发异常)
当合同没有得到支持时,你也可以抛出一个完全的异常,而不是断言,这样程序就会提前终止。您还可以在方法调用站点捕获异常并优雅地处理错误。
存在其他错误处理技术,有些人更喜欢它们而不是异常,但这超出了问题的范围。
- 使用非递归插入方法实现 AVL 树
- C++方法实现:是否可以避免每次都键入类名?
- 如何使用吸气剂方法实现C++封装
- 在C++中使用克隆方法实现多晶型效果
- 使用本机 JNI 静态方法实现C++ Java 运行时错误
- 双向链表插入方法实现 - 正在搜索哪个节点
- 没有虚拟调度的默认方法实现
- C 构造函数和方法实现
- C :如何使用相同的数据类使用不同的方法实现
- 将同一类的方法实现放在不同的对象文件中
- 私有方法实现编译错误
- 使用公共命名方法实现非公共赋值运算符
- 使用 SFINAE 在 Clase 模板中选择不同的方法实现
- 如何根据方法实现的声明顺序对其进行排序
- 使用一个方法实现不同类型赋值的优雅方式,并且没有警告
- 在运行时选择方法实现
- 将参数传递给c++ CORBA方法实现
- 静态constexpr方法实现导致GCC错误
- 包括c++中的头文件(类定义和方法实现)
- 如何在swig生成的代理类中更改特定的方法实现