创建具有受限属性的类型

时间:2019-05-17 14:45:56

标签: c++ design-patterns architecture

在某些情况下,根据某些属性需要限制类型的可能值。需要对示例浮点数或数学向量进行规范化。为这些情况创建类并使用运算符重载在类型之间进行切换是一种好习惯吗?

例如,有一个vector2和vector2_normalized类,其中vector2_normalized的运算符可以更改矢量的长度(+,-,标量*和/,..),返回vector2实例,其他运算符返回vector2_normalized实例。然后使用隐式转换在两者之间自动进行更改。这样必须归一化的向量可以使用这种类型,并消除归一化错误。

4 个答案:

答案 0 :(得分:1)

您在说的这些“限制”称为class invariants,而类是构造域对象以使其有效的一种方法。这是使用类的主要动机之一。

Arno Lepsik最近在CppCon 2018上就名为"Avoiding disasters with strongly typed C++"

的精彩演讲

约翰·拉科斯(John Lakos)在2015年CppCon上也发表了精彩的演讲,名为"Value semantics. It ain't about the syntax"

要完全回答您的问题会很长,因此我希望此简短讨论会有用。

一个很好的例子是Boost.Units

如果您曾经不得不处理编程科学应用程序,那么您就会知道与单位打交道是很痛苦的。

如何确保数据之间的操作有效?您不想增加米的高度,这就是使火箭坠毁的方式。当您的值成为单位的强类型时,在编译时将无法进行这种操作。

答案 1 :(得分:0)

是的,这正是我们拥有private个成员的整个概念的原因。 它的存在是为了消除由于无效成员值而可能发生的所有错误。 这样做是通过公开一个接口(重载的运算符和函数)来代替成员本身的,这样您可以以受控的方式更改这些成员,并相应地调整内部值。

答案 2 :(得分:0)

好吧,这里有std::stringstd::filesystem::path。但是既没有std::uppercase_string,也没有std::russian_string,也没有其他...

看看这些限制是否对您特定类的接口有很大的影响。如果这些限制允许某些全新的操作,这在一般类中是无法想象的,那么它当然值得拥有扩展公共接口的专用类。

我当然可以说是拒绝将有意义的操作伪装为隐式转换。如果转换是不可逆的,则更是如此。这样的转换看起来很诱人,并且可以很好地消除由于疏忽而引起的一些当前错误,但是如果您不注意而无意间进行了转换,则很可能会引入全新的错误。

否则问题就太笼统了……我想没有一种适合所有情况的解决方案。因此,您应该在每种情况下比较优缺点。

答案 3 :(得分:0)

是的-一次警告就回响了AndyG关于类不变式和领域对象的所有说法。

在类型之间允许隐式转换会使您的代码积累无提示转换的风险。通常最好改用显式转换函数。例如,使用

vec2 fun_a();
vec2 fun_b(norm_vec2 const&);
vec2 fun_c(norm_vec2 const&);

你可以写

norm_vec2 v = fun_c(fun_b(fun_a()));

,并且没有注意到发生的隐式转换的数量。至少如果转换是显式的,则可以决定编写norm_vec2函数的重载,或者如果不重要,则可以将其模板化为向量类型。