构建部分重叠的案例陈述的更好方法

Better Way to Structure Case Statements that Partially Overlap

假设案例 1 执行操作 A、B、C、D,案例 2 执行操作 E、B、C、D。有没有比下面更好的方法来构造它?

switch (id)
{
    case 1:
    case 2:
        if (id==1) A();
        if (id==2) E();
        B();
        C();
        D();
        break;
    //More cases below
}

switch (id)
{
    case 1:
        A();
        B();
        C();
        D();
        break;
    case 2:
        E();
        B();
        C();
        D();
        break;
    //More cases below
}

澄清一下:所以我想根据我拥有的对象类型分解要完成的操作。所有这些对象都不共享任何操作,除了这两个对象共享所有操作,除了一个对每个对象都是唯一的。

使用switch构造完全看需要。

在这里而不是 switch if else if 看起来更合适。 在您显示的第一个示例中,switch 没有任何意义,因为您要通过 if 检查并且无论 id 传递给 switch 的情况如何执行的语句都一样。

if(id == 1)
{
  A();
}
else if(id == 2)
{
  B();
}
else if()
{
......
/* Rest of your conditions */
}
else
{

}

没有问题的完整说明,很难知道什么是最好的。这是一个替代方案,它使用 switch case fall-through 来处理问题中的琐碎要求

// handle the two oddball objects
switch (id)
{
    case 1:   A();   break;
    case 2:   E();   break;
}

// handle all the objects
switch (id)
{
    case 1:
    case 2:
        B();
        C();
        D();
        break;
    // other cases
}

就我个人而言,我可能会使用辅助函数,并希望编译器能够适当地内联。假设这三个共享动作形成一个有用的组合似乎是合理的,因为它被调用了不止一次。

void BCD(void) {
  B();
  C();
  D();
}
// ...
switch (id) {
  case 1: A(); BCD(); break;
  case 2: E(); BCD(); break;
  // ...
}

有些人(不是我)可能会说这是 goto 的合法使用,使用相同的参数但不相信编译器优化:

switch (id) {
  case 1: A();
          goto BCD;
  case 2: E();
     BCD: B();
          C();
          D();
          break;
  //...
}

作为对历史的好奇,合法但强烈反对使用不正确的嵌套条件来影响 goto。参见示例 live on ideone.

对于给定的星座,我会使用:

switch (id)
{
    case 1:
        A();
        // add a comment why you do not break here!
    case 2:
        if ( id == 2 )   // the compiler might optimize this
            E();
        B();
        C();
        D();
        break;
    //More cases below
}

聪明的编译器可能会检测到 if 并将其转换为跳过 E();

但实际分组完全取决于整个序列。例如。函数参数可能会改变最佳解决方案。

(1) 也许,您可以将它们放在函数指针中 table.

void (*func[3])() = {0 /*dummy*/, A, B }; 

....

switch (id)
{
    case 1:
    case 2:
        func[id]();
        B();
        C();
        D();
        break;
}

(2) 并且可能也包装其他函数:

void BCD(void){
        B();
        C();
        D();
}

void (*func[3])() = {0 /*dummy*/, A, B }; 

....

switch (id)
{
    case 1:
    case 2:
        func[id]();
        BCD();
        break;
}

这个 "wrap" 在这里是可以的,但如果这些功能恰好发生在 return errors/values.

上,一般来说可能并不理想

(3) 您还可以将 func[id](); 移动到包装器并将 id 传递给 BCD():

void (*func[3])() = {0 /*dummy*/, A, B }; 

void func_calls(int id){
        func[id]();
        B();
        C();
        D();
}

...

switch (id)
{
    case 1:
    case 2:
        func_calls(id);
        break;
}

以上是不是"better"取决于你对更好的定义:)

走这条路以保持概览,以防你有更多这样的情况:

switch (id) 
{
  case 1:
  case 2:

    switch(id)
    {
      case 1:
        A();
        break;

      case 2:
        E();
        break;

      default:
        assert(0);
        break;
    }

    B();
    C();
    D();

    break;

  //More cases below

  default:
    assert(0);
    break;
}

优化由编译器完成。