在交换机的默认标签中放置什么
What to put in a default label of a switch?
假设我有一个枚举。
enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};
后来我有这样的函数:
void Function (ShapeName const shape){
switch (shape){
case ShapeName::TRIANGLE:
DoSomething1();
break;
case ShapeName::CIRCLE:
DoSomething2();
break;
case ShapeName::SQUARE:
DoSomething3();
break;
default:
//THIS CODE BLOCK SHOULD NEVER BE EXECUTED!
}
return;
}
虽然默认标签永远不应该被执行,但我想考虑一下如果程序员向"ShapeName"添加另一个值并且没有在开关中考虑它可能出现的潜在错误。
你会建议我做什么?
1. 断言
我可以使用断言,但我在断言什么?
assert(false); //?
2. 例外情况
我可以抛出一个例外,但我认为这不是很好的做法。 我的印象是,异常是针对由于某些环境而无法预测的运行时事件。
3. 退出
我可以立即退出程序并出现错误。这感觉是最好的主意,但我不确定这是否是好的做法。 我认为断言的优点是,当您准备好发布程序时,您可以将断言全部关闭。然后,所有这些断言代码将不再存在。
也许还有另一种我不知道的方式。 我确实使用了一个编译器标志来警告未解释的值,但我仍然想知道其他人的建议。
用信息丰富的消息断言的想法。试试这个:
assert (!"The default case of so-so switch was reached.");
这始终返回 false,但提供您可以使用的消息。
编辑:
我找到了我从记忆中拉出这个概念的来源;它在下面的书中:
C++编码标准 - 101 规则和准则
对于这种特定情况,即您打开枚举标签并处理所有情况,我的偏好是省略默认值。 这样,对于任何合理的编译器,如果有人将新标记添加到枚举而不是交换机,您将收到有关标记未在交换机中处理的编译时警告。
我想对我来说,这在某种程度上取决于DoSomething#方法的作用。
如果以后会导致不太优雅的崩溃,您肯定希望在调用运行时中断运行时,并解释"使用无效的枚举调用的函数:enumName"或向开发人员发出通知他们没有更新此 switch 语句的内容,而不是让他们想知道以后是否失败。
简短回答:使用多态性来消除问题。
长答案:解决根本问题(即如何防止缺少条目的switch语句?(的最简单方法是避免使用switch语句,如果有可能忘记条目。 switch 语句在本地上下文中很有用,但如果它们表示的逻辑在多个位置重复,则可能会忘记更新一个语句,并且您正在为运行时错误设置自己。
class Shape
{
// functionality MUST be added for new shape types
// or a compile error will occur
virtual void DoSomething() const = 0;
};
void Function (Shape const & shape){
return shape.DoSomething();
}
switch 语句在创建站点可能仍然有用:
enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE};
unique_ptr< Shape > MakeShape (ShapeName const shape){
switch (shape){
case ShapeName::TRIANGLE:
return unique_ptr< Shape >( new Triangle() );
case ShapeName::CIRCLE:
return unique_ptr< Shape >( new Circle() );
case ShapeName::SQUARE:
return unique_ptr< Shape >( new Square() );
}
throw std::runtime_error();
// or whichever option you prefer from the other answers
}
但这是逻辑存在的唯一地方。 甚至这也可以通过静态多态性进行改进:
enum class ShapeName : char {TRIANGLE,CIRCLE,SQUARE,ELLIPSE};
template< ShapeName shape >
unique_ptr< Shape > MakeShape();
template<>
unique_ptr< Shape > MakeShape< ShapeName::TRIANGLE >()
{
return unique_ptr< Shape >( new Triangle() );
}
template<>
unique_ptr< Shape > MakeShape< ShapeName::CIRCLE >()
{
return unique_ptr< Shape >( new Circle() );
}
template<>
unique_ptr< Shape > MakeShape< ShapeName::SQUARE >()
{
return unique_ptr< Shape >( new Square() );
}
int main()
{
MakeShape< ShapeName::TRIANGLE >(); // okay
MakeShape< ShapeName::ELLIPSE >(); // compile error
}
参见 Martin Folwer 了解更多信息。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- #定义c-预处理器常量..我做错了什么
- 努力将整数转换为链表。不知道我在这里做错了什么
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 什么时候在C++中返回常量引用是个好主意
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- C++避免重复声明的语法是什么
- c++库的公共头文件中应该包含什么
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 对两个案例标签使用相同的值与对单个案例使用多个案例标签有什么区别?
- 什么会导致"静态"标签在窗口上不显示WS_VISIBLE
- C++中的标签和枚举调度有什么区别
- 什么是签名目录文件成员标签
- 在交换机的默认标签中放置什么
- 如何将左值转换为右值?以及“新”标签会发生什么
- 我可以使用什么Mac/iOS/便携式库来格式化信息以打印到标签纸上
- 当.h和.cpp Doxygen标签冲突时会发生什么?
- 我们应该在 c++ 类中指定"private"标签吗?有什么区别吗?