Why use prefixes on member variables in C++ classes

前端 未结 29 1410
半阙折子戏
半阙折子戏 2020-11-28 17:39

A lot of C++ code uses syntactical conventions for marking up member variables. Common examples include

  • m_memberName for public members (where public
29条回答
  •  一个人的身影
    2020-11-28 17:53

    When reading through a member function, knowing who "owns" each variable is absolutely essential to understanding the meaning of the variable. In a function like this:

    void Foo::bar( int apples )
    {
        int bananas = apples + grapes;
        melons = grapes * bananas;
        spuds += melons;
    }
    

    ...it's easy enough to see where apples and bananas are coming from, but what about grapes, melons, and spuds? Should we look in the global namespace? In the class declaration? Is the variable a member of this object or a member of this object's class? Without knowing the answer to these questions, you can't understand the code. And in a longer function, even the declarations of local variables like apples and bananas can get lost in the shuffle.

    Prepending a consistent label for globals, member variables, and static member variables (perhaps g_, m_, and s_ respectively) instantly clarifies the situation.

    void Foo::bar( int apples )
    {
        int bananas = apples + g_grapes;
        m_melons = g_grapes * bananas;
        s_spuds += m_melons;
    }
    

    These may take some getting used to at first—but then, what in programming doesn't? There was a day when even { and } looked weird to you. And once you get used to them, they help you understand the code much more quickly.

    (Using "this->" in place of m_ makes sense, but is even more long-winded and visually disruptive. I don't see it as a good alternative for marking up all uses of member variables.)

    A possible objection to the above argument would be to extend the argument to types. It might also be true that knowing the type of a variable "is absolutely essential to understanding the meaning of the variable." If that is so, why not add a prefix to each variable name that identifies its type? With that logic, you end up with Hungarian notation. But many people find Hungarian notation laborious, ugly, and unhelpful.

    void Foo::bar( int iApples )
    {
        int iBananas = iApples + g_fGrapes;
        m_fMelons = g_fGrapes * iBananas;
        s_dSpuds += m_fMelons;
    }
    

    Hungarian does tell us something new about the code. We now understand that there are several implicit casts in the Foo::bar() function. The problem with the code now is that the value of the information added by Hungarian prefixes is small relative to the visual cost. The C++ type system includes many features to help types either work well together or to raise a compiler warning or error. The compiler helps us deal with types—we don't need notation to do so. We can infer easily enough that the variables in Foo::bar() are probably numeric, and if that's all we know, that's good enough for gaining a general understanding of the function. Therefore the value of knowing the precise type of each variable is relatively low. Yet the ugliness of a variable like "s_dSpuds" (or even just "dSpuds") is great. So, a cost-benefit analysis rejects Hungarian notation, whereas the benefit of g_, s_, and m_ overwhelms the cost in the eyes of many programmers.

提交回复
热议问题