C++ 类型字段纯粹是邪恶的吗?

C++ 类型字段纯粹是邪恶的吗?,c++,code-organization,C++,Code Organization,如第12.2.5节所述,与使用虚拟函数和多态性的等效代码相比,类型字段倾向于创建通用性、易出错、直观性和可维护性较差的代码 作为一个简短的示例,下面是如何使用类型字段: void print(const Shape &s) { switch(s.type) { case Shape::TRIANGE: cout << "Triangle" << endl; case Shape::SQUARE: cout << "Squ

如第12.2.5节所述,与使用虚拟函数和多态性的等效代码相比,类型字段倾向于创建通用性、易出错、直观性和可维护性较差的代码

作为一个简短的示例,下面是如何使用类型字段:

void print(const Shape &s)
{
  switch(s.type)
  {
  case Shape::TRIANGE:
    cout << "Triangle" << endl;
  case Shape::SQUARE:
    cout << "Square" << endl;
  default:
    cout << "None" << endl;
  }
}
void打印(const Shape&s)
{
开关(s型)
{
案例形状::三角形:

我不知道有什么实际的例子。人为的例子取决于有什么好的理由不能使用虚拟方法。

当你“知道”的时候你有一个非常具体的、小的、常量的类型集,可以更容易地像这样硬编码它们。当然,常量不是,变量不是,所以在某个时候你可能不得不重写整个过程

这或多或少是一些国家歧视性结合所使用的技术


例如,如果我正在实现一个库,我会知道每个值只能是一个对象、数组、字符串、整数、布尔值或Null。规范不允许任何其他值。

是否存在与虚拟函数和多态性相关的成本?例如,每个类维护一个vtable,每个类对象大小增加4个字节,运行时缓慢(但我从未测量过)为了正确解析虚拟函数。因此,对于简单的情况,使用
类型
字段似乎是可以接受的。

类型枚举可以通过memcpy序列化,而v表不能。类似的功能是,类型枚举值的损坏很容易处理,v表指针的损坏意味着即时不良。没有Portablel甚至测试v表指针有效性的一种方法是调用
dynamic\u cast
typeinfo
对无效对象进行RTTI检查,这是一种未定义的行为


例如,我选择使用由鉴别器控制的静态分派而非动态分派的类型层次结构的一个实例是,通过Windows消息队列传递指向结构的指针。这为我提供了一些保护,防止其他软件从我正在使用的范围中分配广播消息(它应该是为应用程序本地消息保留的,如果您认为该规则实际上得到了遵守,请不要通过GO)。

我认为,如果类型恰好对应于隐含的类,那么类型是错误的。变得复杂的地方是类型不完全匹配或不完全一致


以你的例子来说,如果类型是红色、绿色、蓝色,那该怎么办?这些都是形状的类型。你甚至可以将颜色类作为一个混合,但它可能太多了。

我正在考虑使用类型字段来解决向量切片的问题。也就是说,我想要一个层次对象的向量。例如,我想要我的向量是形状的向量,但是我想储存圆,矩形,三角形等


由于切片的原因,您无法以最简单的方式实现这一点。因此,通常的解决方案是使用指针向量或智能指针。但我认为在某些情况下,使用类型字段将是一种更简单的解决方案,(避免使用新的/删除或替代生命周期技术).

以下指南来自Robert C.Martin的《清洁代码》。 “我对switch语句的一般规则是,如果它们只出现一次,用于创建多态对象,并且隐藏在继承关系后面,以便系统的其他部分看不到它们,则可以容忍它们。”


其基本原理是:如果将类型字段公开给代码的其余部分,则会得到上述switch语句的多个实例。这显然违反了DRY。添加类型时,所有这些开关都需要更改(或者更糟糕的是,它们在不破坏构建的情况下变得不一致)。

这是我能想到的最佳示例(我以前遇到过一个),就是当你的类型集是固定的,你想要做的函数集(取决于这些类型)是流动的。这样,当你添加一个新函数时,你修改了一个地方(添加一个开关)而不是添加一个新的基本虚拟函数,实际实现分散在类型层次结构中的所有类中。

我的看法是:这取决于

参数化方法依赖于此技术

class Creator {
    public:
        virtual Product* Create(ProductId);
};

Product* Creator::Create (ProductId id) {
        if (id == MINE)  return new MyProduct;
        if (id == YOURS) return new YourProduct;
        // repeat for remaining products...

        return 0;
}

那么,这是不是很糟糕。我不这么认为,因为我们在这个阶段没有任何其他选择。这是一个绝对必要的地方,因为它涉及到对象的创建。对象的类型尚不清楚

然而,OP中的例子确实需要重构。这里我们已经在处理一个现有的对象/类型(作为参数传递给函数)

如上文所述—

“关闭:避免打开电源 要自定义的对象的类型 行为。使用模板和虚拟 函数让类型(而不是它们的 调用代码)来决定他们的行为。“


在惯用的C++中,你可以通过引用而不是指针来传递形状。事实上,你很可能使用const引用。我已经见过这类事情是由老C程序员编写的代码。我怀疑他们没有意识到更好的方法,或者不想学习它。——1:没有人应该写任何语言特征是PU。re-evil'@Jay:这不是一个“语言特性”,它是许多语言特性的一个潜在应用。在任何图灵完备语言中,你都可以做一些可以称为“纯邪恶”的事情。@Jay:好吧,那它就是一个不纯洁的邪恶。:-)+1:一个明显的例子是,一个小的、恒定的类型集是一个不太可能快速改变的外部标准(例如,ISO标准需要相当长的时间才能改变,即使是最好的情况)好的,我看了一篇文章,但是我没有看到任何东西能说服我在C++中使用帕斯卡风格的工会,而不是仅仅通过虚拟方法来利用多态性。我缺少什么?我写了一个JSON库,尽管JSON级别的对象数量有限,但是我很容易实现多个O。ne型