验证输入的好方法是什么?
What is a good way to validate input?
我有一个类,其中一些成员的值有一个有限的范围。例如
class Sphere
{
public:
void setRadius(double radius)
{
m_radius = radius;
}
private:
double m_radius; // must >= 0.
};
我也有一个输入半径的对话框。我可以在setRadius()方法中检查半径验证,或者在对话框中检查。哪一种方式更好?这似乎是一个相当普遍的问题。什么是传统的或最好的方式?谢谢。
我假设将根据用户输入调用set方法。如果是这样,常规的方法是set方法在提供异常值时抛出异常。该异常应该一直传播到UI
在OOP中,通常让验证发生在函数中,如果值不在您的可接受范围内,则让函数抛出异常。
然而,如果你正在为一个类做这件事,并且还不希望知道抛出/捕获异常,你可以做以下两件事之一:
- 让你的函数返回int, bool等。如果参数在范围内,那么你的函数返回一些值来表示。否则,函数返回一些值,指示参数不在范围内。
像这样:
bool setRadius(double radius)
{
if(radius >= 0)
{
m_radius = radius;
return true;
}
else return false;
}
注意,如果"radius"的参数不在你的范围内,你不能初始化/改变存储在m_radius中的值。将m_radius的值更改为不可接受的值是没有意义的——这是浪费时间。
- 检查main() ("in the dialog"?)
如果你想知道更多关于异常的知识,你可以参考这个页面来更好地理解什么是异常:http://www.cplusplus.com/doc/tutorial/exceptions/
所以,i++,总结一下,约定是在方法中检查它,如果值超出可接受范围,则让方法抛出异常。如果你正在上课并且还没有涉及异常,你可能不需要。祝你好运!:)
我可以在setRadius()方法中检查半径验证,或者检查在对话中。哪一种方式更好?
如果系统真的很小,并且GUI相对简单,您可以在对话框类中检查输入。另一个解决方案是提供第三类输入验证策略,用于检查用户输入。
下面是一个非常简单的演示代码,可以使用模板为不同的GUI设置不同的策略。
class CheckPolicy
{
public:
CheckPolicy() {}
virtual bool ValidInput(double f)
{
return f > 0;
}
};
class GUI
{
public:
GUI(){}
void GetInput()
{
float f = 1.0f;
if (policy_.ValidInput(f))
{
sphere_.setRadius(f);
}
}
private:
CheckPolicy policy_;
Sphere sphere_;
};
我建议采用一种不同于其他方法的方法。我就把值存储在这里。相反,看看我的水晶球,当在球体上调用Render(Image& target)
函数时,我将验证所有参数是否合适。也可以采用混合方法,在setter中验证半径是非负浮点数,同时在渲染时验证球体是否在图像的边界内。
这两种方法有一个根本的区别:
- 不允许半径变为负值意味着非负半径是类不变量。将所有类不变量的验证放入一个实用程序函数中,通过RAII助手在所有(变化的)成员函数的进入和退出时调用该实用程序函数,这对于调试是一件好事,因为当内部状态(可能比单个标量更复杂)以某种方式变得不一致时,它会立即捕获。为了提高速度,我通常对发布二进制文件禁用这些检查,这样即使进行广泛的检查,也不会损失任何性能。
- 允许半径变为负值,但稍后引发异常会将其转换为由使用该值的操作(例如渲染)引起的故障。在某些情况下,这使得无效输入值在操作期间与内存不足无法区分,但它的优点是您只需要在一个地方捕获这些错误。
在我看来,这是太多的面向对象。对于少于2 - 3个变量,我不会创建具有getter-setter和私有数据的类——这没有意义。它需要大量不必要的代码。
您最好在UI前端进行数据验证(例如通过DoDataExchange
)。
如果必须设计一个类来保存数据并进行数据验证,请使用模板!
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- C++从另一个类访问公共静态向量的正确方法是什么
- 在 c++ 中拥有一组结构的正确方法是什么?
- 通过JNI传递数据数组的最快方法是什么
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 在另一个类视图中添加最多2个图表的正确方法是什么
- 在C++中样板"冷/never_inline"错误处理技术的最佳方法是什么?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 在C++中包含原型文件的正确方法是什么?
- 在 OpenCV C++ 中估计基本矩阵之前对相应点进行归一化的正确方法是什么?
- 在PostgreSQL中根据它们的ID选择大量行的最快方法是什么?
- 在OSX上使用CMake将Adobe的XMP工具包构建为共享库的最简单方法是什么?
- 将一系列整数放入类的最佳方法是什么?
- 从长整整转换为uint64_t的推荐方法是什么?
- C++:使用方法调用析构函数的顺序是什么?
- 将此布尔值传递给此函数的最有效方法是什么?