【发布时间】:2014-09-05 12:35:01
【问题描述】:
考虑一下我有一些同时具有枚举和类行为的“东西”。例如,考虑一个有颜色概念的世界,正好有 3 个:红色、绿色和蓝色。
基于这个颜色,我们还有一些功能,例如我们可以有一个函数告诉我们一个颜色是否是一个快乐的颜色,以及一些其他的函数:
isHappy: Color -> {yes, no}
intensity: Color -> value
rotate: Color -> Color
要完成类似 haskel 的语法,我们可以这样做:
data Color = Red | Green | Blue
并实现上述功能。但那是haskell,它不是C++,也没有像c++那样的OO概念。继续使用 C++:
事实上我们只有 3 种颜色,仅此而已,这表明使用枚举;允许我们在源代码的任何地方使用红色、蓝色和绿色等常量。但是,我们不能向枚举添加方法,因此 isHappy 强度和旋转将被实现为函数(而不是方法)。
我们有这些方法的第一个参数是颜色的事实,建议使用一个类。但是,我们可以实例化任意数量的此类类,尤其是超过 3 个。这意味着代表 Red 的两个变量将被分配到内存中的不同位置。这有点奇怪,因为 Red 将具有非常“类似常量”的行为,因为它是不可变的,并且只能创建三种不同类型的 Color 对象。此外,我们不能使用红色、绿色和蓝色等符号,而是需要将它们存储在变量中。恕我直言,使用全局变量会非常难看。
我们还可以使用继承,其中 Red、Green 和 Blue 从 Color 类继承。这使我们可以非常轻松地微调功能,因为我们可以在任何我们想要的类中实现我们想要的。但是,在 c++ 中具有继承的 OO 应用了切片。例如,创建一个包含(红色、绿色或蓝色)列表的向量会非常棘手。或者创建一个存储三种颜色之一的变量:
Color c1 = Red();
Color c2 = Blue();
变量 c1 和 c2 将被分配一个不同的对象,但没有办法真正区分它们。这使得实现 operator== 变得棘手:
class Red : Color { //...
bool operator==(Color &c) const{
// no way to determine whether c is Red, Green or Blue.
}
}
对于这种情况是否有有效的模式或解决方案?我认为它出现了很多,因此我很好奇。也非常感谢仅 C++14 的解决方案!
编辑:许多人似乎评论说,我提到的解决方案的问题并不是真正的问题。这是一个有效的观点。但是,我不是在寻找可能的解决方案,而是在寻找符合良好 c++(11|14) 设计原则的解决方案。我也可以使用:
#define RED 0
#define GREEN 1
#define BLUE 2
这样可以很好地工作,但它不是一个好的设计原则,因为它可能会与使用红色、蓝色或绿色等名称的其他功能发生冲突。这在语义上也很奇怪,因为我可以说 RED
总之,在答案中,我希望看到一个遵循良好 c++ 设计原则的解决方案。我不在乎可行的解决方案!这可能是前面提到的三种方式之一,使用枚举、一个类或继承。
EDIT2: 同时,我还考虑了针对多继承情况的基于模板的方法。然而,老实说,我对模板的了解还不足以创建“好”的东西。该想法基于 type_traits 标头的 std::is_same 和 std::is_functional 等函数。
#include <iostream>
class Color {};
class Red : Color {};
class Green : Color {};
class Blue : Color {};
template<class C1, class C2>
bool is_same_color();
template<class C1>
bool is_happy();
int main() {
// your code goes here
return 0;
}
它不起作用,但我希望这个想法得到解决。另外,我意识到 is_same_color 和 is_happy 应该是定义了 operator() 的类。
EDIT3:可以说这就是我想要的:
enum Color {
RED, GREEN, BLUE
bool isHappy() { return this==GREEN || this==RED; }
Color rotate() { return (this==RED ? GREEN (this==GREEN ? BLUE : RED)); }
int intensity() { return (this==RED ? 11 (this==GREEN ? 12 : 4)); }
}
但这当然不是有效的 c++。
【问题讨论】:
-
我看不出有什么紧迫的理由说明那些不能成为免费函数而必须“成为 OO”,不管这意味着什么。
-
可能有一个
Color类,其中嵌入了颜色枚举,并有Red、Blue等创建适当对象的函数。将它与一些运算符重载(例如operator==)混合,它可能会做你想做的事? -
“这意味着代表 Red 的两个变量,仍然会将 red1 == red2 评估为 false。” ...为什么?
-
@Herbert 假设您没有实现某些功能,您将不会拥有该功能。这几乎不是一个相关的设计观点。你在问如何设计东西,让它按照你想要的方式运行。 C++ 允许你重载
operator ==,因此你应该认为这是可行的。 -
Red 是一个常量值,而不是一个类。颜色可能是一个类。