【问题标题】:C++ How to replace #defines with constsC ++如何用常量替换#defines
【发布时间】:2013-06-08 01:49:55
【问题描述】:

最近我一直在认真研究我的编程风格以及如何改进它。首先让我说,在我目前的角色中,我是唯一的程序员。因此,我可以随心所欲地把事情弄得乱七八糟,但我真的在努力成为一个更好、更健全的程序员。

另外,我的背景主要是基于 C 的,必要时基本上使用 C++ 作为 C 的超集。结果,我偶然发现了以下难题。

我总是用类似 #define ERROR_FUNCTION_BLEW_UP -2 的东西定义错误代码。老实说,我可以看到这样做的好处,因为我不必分配内存来存储 -2。但是,在 C++ 中,我可以看到使用 const 变量的好处,因为两个竞争宏之间发生冲突的可能性较小。

因此,我想知道在 C++ 中实现错误代码最简洁的方法是什么。也就是说,我希望客户端能够通过执行类似于“if (return_value == ERROR_FUNCTION_BLEW_UP)”的操作来检查某些函数的返回值。我尝试在每个类中添加一个 const 变量,但是代码看起来不正确。也就是说,客户端现在检查“if (return_value == MyClass.kErrorFunctionBlewUp_)”的内容。有没有更简洁的方法来实现这一点,而不是让常量成为类的公共成员?

另外,补充一下我的问题,myClass 是一个基类,现在我想在 MyDerivedClass 中添加更多错误代码。解决此问题并避免使用宏的最佳方法是什么?

感谢大家的帮助。

【问题讨论】:

    标签: c++ constants c-preprocessor


    【解决方案1】:

    使用enums:

    enum Errors
    {
        NO_ERROR = 0,
        FUNCTION_BLEW_UP,
        WTF_THIS_SHOULDNT_HAPPEN,
    };
    

    此外,如果更合适,请考虑使用异常(查看std::exception)。

    【讨论】:

    • 感谢您的快速响应。我做了一些初步的研究,但我仍然有一些疑问:1.定义枚举的“最佳”位置在哪里?也就是说,我是否将它放在类之前的文件顶部,以确保客户端通过包含我的文件来接收它? 2. 我现在是否必须更改返回错误代码的函数以返回枚举类型? 3.我如何处理派生类的情况?也就是说,派生类应该接受基类错误的所有属性,但添加一些自己的属性。感谢您的帮助!
    • 使用枚举有利有弊。如果您不滥用强制转换,您可以获得一些类型安全性,防止为错误的参数使用错误的名称等;如果您打开相关的编译器警告,它还会让您知道您是否没有检查 switch 语句中的特定值。缺点:当你将它们用于标志之类的东西时,你最终会经常进行强制转换。使用它们的一种流行方法是执行以下操作:enum COFFEE_ROAST_TYPE { COFFEE_ROAST_TYPE_DARK, COFFEE_ROAST_TYPE_GO_HOME, MAX_COFFEE_ROAST_TYPES };
    • @kfsone - 如果您使用枚举作为标志,请重载适当的位运算符。您不必在运算符之外编写强制转换。
    • @kfsone:如果您将它们用作标志,则存储标志组合的类型应该是intunsigned int 类型。例如:int x = enumFlag1 | enumFlag2;
    • 不,当使用它们作为标志时,如果你想要类型安全,就按照 Pete 所说的去做。
    【解决方案2】:

    如果您真的只想替换宏,请将它们替换为常量。常量具有内部链接(即仅限于翻译单元(“文件”)),因此编译器可以轻松地用常量内联替换它们的使用,而无需使用比宏更多或更少的单个字节。请注意,习惯上将 ALL_UPPERCASE 保留为宏,因为宏不遵循正常的代码约定,因此您也必须更改它。

    然后,在 C++ 中,您通常不使用调用者必须检查的返回码,而是使用自动传播的异常。如果要保留错误代码,可以使用枚举或常量并将它们放入命名空间。请注意,枚举会泄漏到周围的命名空间或类中,因此最好将它们包裹在一层:

    namespace errorcode
    {
        enum type
        {
            printer_on_fire,
            volume_not_formatted,
            bluescreen
        };
    }
    

    异常有时确实包含错误代码,这些错误代码进一步说明了失败的原因。这是指定它们的一种方法:

    struct error:
        std::runtime_error
    {
        ...
    
        enum code
        {
            printer_on_fire,
            volume_not_formatted,
            bluescreen
        };
    
        code fault;
    };
    

    注意不必嵌套代码,也可以用上面已有的errorcode::type构建异常类型。不过,一些嵌套很有用,因为枚举会污染周围的命名空间。

    也就是说,你问“我是不是在上课前把它放在文件的顶部”,但在这里你有一个误解。首先,并非每个文件都包含一个类。然后,并非每个包含类的文件都包含其中一个。例如,如果错误代码的集合被整个类层次结构使用,那么在单独的文件中定义它是有意义的,以明确它不属于其中一个,并且可以在相关的非类中使用功能也一样。在那个文件中,你也会坚持例如将其转换为字符串以进行调试的函数,并且可能是带有其中之一的异常类型。

    【讨论】:

      猜你喜欢
      • 2011-07-12
      • 2010-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      • 2014-08-03
      相关资源
      最近更新 更多