186

我经常在主要与游戏开发相关的教程、示例和其他代码中看到m_用于变量m_World、 、...)的前缀。m_Sprites

为什么人们m_要为变量添加前缀?

4

10 回答 10

135

这是定义作为成员变量的变量的典型编程实践。因此,当您稍后使用它们时,您无需查看它们的定义位置即可知道它们的范围。如果您已经知道范围并且正在使用诸如intelliSense 之类的东西,这也很棒,您可以开始m_并显示所有成员变量的列表。匈牙利符号的一部分,请参阅此处示例中有关范围的部分。

于 2012-10-21T14:56:08.367 回答
113

Clean Code: A Handbook of Agile Software Craftsmanship中,明确建议不要使用此前缀:

您也不再需要为成员变量添加前缀m_。你的类和函数应该足够小以至于你不需要它们。

还有一个例子(C#代码):

不良做法:

public class Part
{
    private String m_dsc; // The textual description

    void SetName(string name)
    {
        m_dsc = name;
    }
}

好习惯:

public class Part
{
    private String description;

    void SetDescription(string description)
    {
        this.description = description;
    }
}

在显式歧义(description成员和description参数)的情况下,我们使用语言结构来引用成员变量this

于 2014-10-25T15:20:24.580 回答
25

这是 C++ 中的常见做法。这是因为在 C++ 中,成员函数和成员变量不能有相同的名称,而且 getter 函数的命名通常不带“get”前缀。

class Person
{
   public:
      std::string name() const;

   private:
      std::string name; // This would lead to a compilation error.
      std::string m_name; // OK.
};

main.cpp:9:19: error: duplicate member 'name'
      std::string name;
                  ^
main.cpp:6:19: note: previous declaration is here
      std::string name() const;
                  ^
1 error generated.

http://coliru.stacked-crooked.com/a/f38e7dbb047687ad

“m_”表示“成员”。前缀“_”也很常见。

您不应该在通过使用不同约定/语法来解决此问题的编程语言中使用它。

于 2017-01-14T18:24:37.257 回答
12

m_前缀通常用于成员变量 - 我认为它的主要优点是它有助于在公共属性和支持它的私有成员变量之间建立明显的区别:

int m_something

public int Something => this.m_something; 

为支持变量建立一致的命名约定会有所帮助,而m_前缀是这样做的一种方式——一种适用于不区分大小写的语言的方式。

这有多有用取决于您使用的语言和工具。具有强大重构工具和智能感知的现代 IDE 对此类约定的需求较少,这当然不是这样做的唯一方法,但无论如何都值得了解这种做法。

于 2012-10-21T22:25:43.623 回答
9

如其他答案所述,m_前缀用于指示变量是类成员。这与匈牙利表示法不同,因为它不表示变量的类型,而是表示它的上下文。

m_在 C++ 中使用,但在其他一些必须使用“this”或“self”的语言中不使用。我不喜欢看到'this->' 与 C++ 一起使用,因为它会使代码混乱。

另一个答案m_dsc是“不良做法”和“描述”;是“好的做法”,但这是一个红鲱鱼,因为问题是缩写。

另一个答案说键入this会弹出 IntelliSense,但任何好的 IDE 都会有一个热键来为当前类成员弹出 IntelliSense。

于 2017-06-15T08:39:07.190 回答
8

Lockheed Martin 使用 3 前缀命名方案,使用起来非常棒,尤其是在阅读其他人的代码时。

   Scope          Reference Type(*Case-by-Case)   Type

   member   m     pointer p                       integer n
   argument a     reference r                     short   n
   local    l                                     float   f
                                                  double  f
                                                  boolean b

所以...

int A::methodCall(float af_Argument1, int* apn_Arg2)
{
    lpn_Temp = apn_Arg2;
    mpf_Oops = lpn_Temp;  // Here I can see I made a mistake, I should not assign an int* to a float*
}

拿走它的价值。

于 2019-10-25T15:47:28.153 回答
3

正如许多其他回复中所述,m_ 是表示成员变量的前缀。它在/曾经在 C++ 世界中普遍使用,并且也传播到其他语言,包括 Java。

在现代 IDE 中,它是完全多余的,因为语法突出显示哪些变量是本地变量以及哪些是成员变量是显而易见的。然而,到 90 年代后期出现语法高亮时,该约定已经存在多年并且已经牢固确立(至少在 C++ 世界中)。

我不知道您指的是哪些教程,但我猜他们使用约定是由于以下两个因素之一:

  • 它们是 C++ 教程,由习惯于 m_ 约定的人编写,和/或...
  • 他们用纯文本(等宽)编写代码,没有语法高亮,因此 m_ 约定有助于使示例更清晰。
于 2017-08-04T09:16:38.377 回答
2

为了完成当前的答案并且由于问题不是特定于语言的,一些 C 项目使用前缀m_来定义特定于文件g_的全局变量 - 以及范围大于它们定义的文件的全局变量。
在这种情况下,使用前缀定义的全局变量m_ 应定义为static.

有关使用此约定的项目示例,请参阅EDK2(一种 UEFI 开源实现)编码约定。

于 2018-08-22T12:21:33.427 回答
1

我还没有看到的一个论点是m_可以使用诸如前缀之类的前缀来防止名称与#define'd 宏's 冲突。

正则表达式从 curses/ncurses#define [a-z][A-Za-z0-9_]*[^(]中搜索。/usr/include/term.h

于 2019-02-15T21:17:34.327 回答
1

其他人提到它意味着一个班级成员。Qt 是一个流行的 C++ 框架,它使用这种表示法,所以很多 C++ GUI 教程都使用m_. 你可以看到他们几乎所有的例子都m_用于班级成员。就个人而言,我使用m_它是因为它比它短this->并且感觉紧凑。

于 2021-04-07T05:31:40.843 回答