[英]Question about using a switch statement
首先,我意识到从性能角度来看,此switch语句的设计很慢,因为在某些情况下cout被多次调用。 除此之外,这种编写switch语句的样式不是好的编码实践。 换句话说,单独处理每个案例并打破还是会更好?
int main(void)
{
int number;
cout << "Enter a number between 1 and 10 and I will display its Roman numeral equivalent." << endl
<< "> ";
cin >> number;
cout << "Roman numeral: ";
switch (number)
{
case 3:
cout << "I";
case 2:
cout << "I";
case 1:
cout << "I";
break;
case 4:
cout << "I";
case 5:
cout << "V";
break;
case 6:
cout << "VI";
break;
case 7:
cout << "VII";
break;
case 8:
cout << "VIII";
break;
case 9:
cout << "I";
case 10:
cout << "X";
break;
default:
cout << "Error!\nYou did not enter a number between 1 and 10";
}
cout << endl;
return 0;
}
switch语句并不慢,它们通常已被编译器优化为跳转表。 而且,如果您确定switch语句可以按预期工作,那很好,并且是执行此操作的一种很酷的方法。
就是说,如果您单独处理每个案件,您将拥有相同数量的案件。 如果这就是您要做的一切,那么我可能会更改它以分别处理每个对象,而不会失败。 这样更容易理解和维护:
switch (number)
{
case 1:
cout << "I";
break;
case 2:
cout << "II";
break;
case 3:
cout << "III";
break;
case 4:
cout << "IV";
break;
case 5:
cout << "V";
break;
case 6:
cout << "VI";
break;
case 7:
cout << "VII";
break;
case 8:
cout << "VIII";
break;
case 9:
cout << "IX";
break;
case 10:
cout << "X";
break;
default:
cout << "Error!\nYou did not enter a number between 1 and 10";
}
而像@paxdiablo建议,以增强可读性,你可以把情况下,语句和break
都在同一行,如果它看起来更好的给你:
case 1: cout << "I"; break;
case 2: cout << "II"; break;
// etc.
这是一个简单的案例,很难说它真的很“糟糕”。 我听过关于出租案的不同意见。 我敢肯定,在某些时候,我们都做到了。 (我通常使用/ * FALL-THROUGH * /这样的文件将其清楚地记录下来,以便下一个阅读代码的人知道我打算这样做。)
我认为一个更复杂的例子将证明这不是一个好主意。 但这并不是真的,因为失败本身就是一件坏事。 但是因为更好的设计并不能保证。 在面向对象的设计中,一条case语句可能表明您有“代码味道”-您不是在让对象根据类型而不是根据其他一些信息来做它需要做的事情。
现在,如果有人真的想对您公认的简单示例挑剔,那么您可能会说您正在以不好的方式将控制器,模型和视图混合在一起。 您的控制器应该只获取输入。 您的模型将有更好的方法来获取输入的备用表示形式(映射或heck,case语句,I dunno),并且视图逻辑不会分散在控制器逻辑中或周围。 通过实际上遵循其他一些设计概念,switch语句可能会完全消失。 其他示例也可能发生这种情况。
简而言之,我认为如果您的设计是合理的,那么您可能会发现,即使实际上甚至有必要使用switch语句,对于后备case语句的担心也没什么大不了的。
我倾向于不使用这种样式,因为通常很难一目了然地掌握控制流程。 这就是为什么goto
通常被认为是一个不好的主意的原因之一(尽管有些人在不理解其原因的情况下将其作为福音-在某些情况下,只要它不会使代码变得不可读,它实际上就很方便)。
换句话说,我希望每种case
都独立。 如果它们具有共同性,我倾向于将其分解为单独的函数,并在每种情况下都调用这些函数。
这不包括代码在不同情况下是相同的情况,而我只使用类似(伪代码,显然)的代码:
case 1: case 2: case 3:
print "It's one, two or three"
对于您的特定用例,我可能只会使用类似以下的表查找:
char *roman[] = {"I", "II", "III", "IV", ... "X"};
if ((n < 1) || (n > 10))
cout << "Urk! I only have ten fingers!";
else
cout << roman[n-1];
只是为了保持(源代码)紧凑。
对于每种情况,都应使用“间隔”选项。 使用“直通”将在下一种情况下继续执行代码,这可能会导致错误并影响性能。
没错,多次调用“ <<”运算符会产生一定的开销。 但是,您在这里谈论的是两个语句,因此这可能不是优化的重点。
如果要优化代码,为什么不使用包含罗马数字的静态字符串数组呢? 像roman [0] =“ I”,roman [1] =“ II”等,我怀疑这种表示形式会比上述函数花费更多的内存,并且摆脱了膨胀的switch语句。
那非常聪明,而且很快。 但是,如果您想提高性能...
cout
的字符串添加到正在运行的字符串缓冲区中。 然后,switch语句后, cout
缓冲区。 编译器可以将switch语句优化为跳转表,因此它们并不总是很慢。 而且它们绝对比编写一堆if
- else if
语句更好。 我个人喜欢失败,因为它允许您在某些情况下做一些很酷的事情,而不必重复代码。 但总的来说,它们并不容易理解,因为与单独处理每个案例相比,它们很难理解。
至于你的例子,如果你担心多次调用cout
,你总是可以存储在中间串stringstream
和打印,最后一个字符串。 但是,输出到cout
是经过缓冲的,因此我不知道这样做是否会显着改善性能。
#include <iostream>
#include <ios>
#include <sstream>
int main(void)
{
using namespace std;
int number = -1;
cout << "Enter a number between 1 and 10 and I will display its Roman numeral equivalent." << endl
<< "> ";
cin >> number;
ostringstream oss( "Roman numeral: ", ios_base::ate );
switch (number)
{
case 3:
oss << "I";
case 2:
oss << "I";
case 1:
oss << "I";
break;
case 4:
oss << "I";
case 5:
oss << "V";
break;
case 6:
oss << "VI";
break;
case 7:
oss << "VII";
break;
case 8:
oss << "VIII";
break;
case 9:
oss << "I";
case 10:
oss << "X";
break;
default:
cout << "Error!\nYou did not enter a number between 1 and 10";
return -1;
}
cout << oss.str() << endl;
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.