为什么在 C++ 类中的成员变量上使用前缀
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1228161/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why use prefixes on member variables in C++ classes
提问by VoidPointer
A lot of C++ code uses syntactical conventions for marking up member variables. Common examples include
许多 C++ 代码使用语法约定来标记成员变量。常见的例子包括
- m_memberNamefor public members (where public members are used at all)
- _memberNamefor private members or all members
- m_ memberName用于公共成员(完全使用公共成员)
- _成员名称的私有成员或全体成员
Others try to enforce using this->memberwhenever a member variable is used.
其他人试图在使用成员变量时强制使用 this->成员。
In my experience, most larger code bases fail at applying such rules consistently.
根据我的经验,大多数较大的代码库都无法始终如一地应用这些规则。
In other languages, these conventions are far less widespread. I see it only occasionally in Java or C# code. I think I have never seen it in Ruby or Python code. Thus, there seems to be a trend with more modern languages to not use special markup for member variables.
在其他语言中,这些约定远没有那么普遍。我只是偶尔在 Java 或 C# 代码中看到它。我想我从未在 Ruby 或 Python 代码中见过它。因此,更现代的语言似乎有一种趋势,即不对成员变量使用特殊标记。
Is this convention still useful today in C++ or is it just an anachronism. Especially as it is used so inconsistently across libraries. Haven't the other languages shown that one can do without member prefixes?
这个约定今天在 C++ 中是否仍然有用,还是只是一个时代错误。特别是因为它在库中的使用如此不一致。其他语言没有表明可以不用成员前缀吗?
采纳答案by Juan
You have to be careful with using a leading underscore. A leading underscore before a capital letter in a word is reserved. For example:
使用前导下划线时必须小心。保留单词中大写字母前的前导下划线。例如:
_Foo
_Foo
_L
_L
are all reserved words while
都是保留字,而
_foo
_foo
_l
_l
are not. There are other situations where leading underscores before lowercase letters are not allowed. In my specific case, I found the _L happened to be reserved by Visual C++ 2005 and the clash created some unexpected results.
不是。在其他情况下,不允许在小写字母前使用下划线。在我的特定情况下,我发现 _L 恰好被 Visual C++ 2005 保留,并且冲突产生了一些意想不到的结果。
I am on the fence about how useful it is to mark up local variables.
我对标记局部变量有多大用持怀疑态度。
Here is a link about which identifiers are reserved: What are the rules about using an underscore in a C++ identifier?
这是一个关于保留哪些标识符的链接:在 C++ 标识符中使用下划线的规则是 什么?
回答by Jason Williams
I'm all in favour of prefixes done well.
我完全赞成前缀做得好。
I think (System) Hungarian notation is responsible for most of the "bad rap" that prefixes get.
我认为(系统)匈牙利符号是前缀获得的大部分“坏说唱”的原因。
This notation is largely pointless in strongly typed languages e.g. in C++ "lpsz" to tell you that your string is a long pointer to a nul terminated string, when: segmented architecture is ancient history, C++ strings are by common convention pointers to nul-terminated char arrays, and it's not really all that difficult to know that "customerName" is a string!
这种表示法在强类型语言中基本上毫无意义,例如在 C++ "lpsz" 中,它告诉你你的字符串是一个指向以 nul 结尾的字符串的长指针,当: 分段体系结构是古老的历史,C++ 字符串按照惯例是指向以 nul 结尾的指针char 数组,知道“customerName”是一个字符串并不是那么困难!
However, I do use prefixes to specify the usageof a variable (essentially "Apps Hungarian", although I prefer to avoid the term Hungarian due to it having a bad and unfair association with System Hungarian), and this is a very handy timesavingand bug-reducingapproach.
但是,我确实使用前缀来指定变量的用法(本质上是“Apps Hungarian”,尽管我更喜欢避免使用术语 Hungarian,因为它与 System Hungarian 有不良和不公平的关联),这是一个非常方便的节省时间和减少错误的方法。
I use:
我用:
- m for members
- c for constants/readonlys
- p for pointer (and pp for pointer to pointer)
- v for volatile
- s for static
- i for indexes and iterators
- e for events
- m 为会员
- c 用于常量/只读
- p 代表指针(pp 代表指向指针的指针)
- v 为 volatile
- s 为静态
- i 用于索引和迭代器
- e 用于事件
Where I wish to make the typeclear, I use standard suffixes (e.g. List, ComboBox, etc).
在我希望明确类型的地方,我使用标准后缀(例如 List、ComboBox 等)。
This makes the programmer aware of the usageof the variable whenever they see/use it. Arguably the most important case is "p" for pointer (because the usage changes from var. to var-> and you have to be much more careful with pointers - NULLs, pointer arithmetic, etc), but all the others are very handy.
这使程序员无论何时看到/使用变量都知道它的用法。可以说,最重要的情况是指针的“p”(因为用法从 var. 更改为 var-> 并且您必须更加小心指针 - NULL、指针算术等),但所有其他情况都非常方便。
For example, you can use the same variable name in multiple ways in a single function: (here a C++ example, but it applies equally to many languages)
例如,您可以在单个函数中以多种方式使用相同的变量名:(这里是一个 C++ 示例,但它同样适用于许多语言)
MyClass::MyClass(int numItems)
{
mNumItems = numItems;
for (int iItem = 0; iItem < mNumItems; iItem++)
{
Item *pItem = new Item();
itemList[iItem] = pItem;
}
}
You can see here:
你可以在这里看到:
- No confusion between member and parameter
- No confusion between index/iterator and items
- Use of a set of clearly related variables (item list, pointer, and index) that avoid the many pitfalls of generic (vague) names like "count", "index".
- Prefixes reduce typing (shorter, and work better with auto-completion) than alternatives like "itemIndex" and "itemPtr"
- 成员和参数之间没有混淆
- 索引/迭代器和项目之间没有混淆
- 使用一组明确相关的变量(项目列表、指针和索引),避免了“计数”、“索引”等通用(模糊)名称的许多陷阱。
- 与诸如“itemIndex”和“itemPtr”之类的替代方案相比,前缀减少了输入(更短,并且在自动完成时效果更好)
Another great point of "iName" iterators is that I never index an array with the wrong index, and if I copy a loop inside another loop I don't have to refactor one of the loop index variables.
“iName”迭代器的另一个优点是我从不索引错误索引的数组,如果我在另一个循环中复制一个循环,我不必重构其中一个循环索引变量。
Compare this unrealistically simple example:
比较这个不切实际的简单例子:
for (int i = 0; i < 100; i++)
for (int j = 0; j < 5; j++)
list[i].score += other[j].score;
(which is hard to read and often leads to use of "i" where "j" was intended)
(这很难阅读并且经常导致使用“i”,而“j”是本意)
with:
和:
for (int iCompany = 0; iCompany < numCompanies; iCompany++)
for (int iUser = 0; iUser < numUsers; iUser++)
companyList[iCompany].score += userList[iUser].score;
(which is much more readable, and removes all confusion over indexing. With auto-complete in modern IDEs, this is also quick and easy to type)
(这更具可读性,并消除了索引的所有混淆。通过现代 IDE 中的自动完成功能,这也可以快速且易于输入)
The next benefit is that code snippets don't require any contextto be understood. I can copy two lines of code into an email or a document, and anyone reading that snippet can tell the difference between all the members, constants, pointers, indexes, etc. I don't have to add "oh, and be careful because 'data' is a pointer to a pointer", because it's called 'ppData'.
下一个好处是代码片段不需要理解任何上下文。我可以将两行代码复制到电子邮件或文档中,任何阅读该片段的人都可以分辨出所有成员、常量、指针、索引等之间的区别。我不必添加“哦,要小心,因为'data' 是一个指向指针的指针”,因为它被称为 'ppData'。
And for the same reason, I don't have to move my eyes out of a line of code in order to understand it. I don't have to search through the code to find if 'data' is a local, parameter, member, or constant. I don't have to move my hand to the mouse so I can hover the pointer over 'data' and then wait for a tooltip (that sometimes never appears) to pop up. So programmers can read and understand the code significantlyfaster, because they don't waste time searching up and down or waiting.
出于同样的原因,我不必为了理解一行代码而将视线移开。我不必搜索代码来查找“数据”是本地、参数、成员还是常量。我不必将手移到鼠标上,这样我就可以将指针悬停在“数据”上,然后等待工具提示(有时从不出现)弹出。所以,程序员可以阅读和理解的代码显著更快,因为他们没有时间浪费在寻找上下或等待。
(If you don't think you waste time searching up and down to work stuff out, find some code you wrote a year ago and haven't looked at since. Open the file and jump about half way down without reading it. See how far you can read from this point before you don't know if something is a member, parameter or local. Now jump to another random location... This is what we all do all day long when we are single stepping through someone else's code or trying to understand how to call their function)
(如果你不认为你浪费时间上下搜索来解决问题,找一些你一年前写的代码,从那以后就没有看过。打开文件,跳到一半而不读它。看看如何在你不知道某个东西是成员、参数还是本地之前,你可以从这一点读到很远。现在跳到另一个随机位置......当我们单步执行别人的代码时,这就是我们整天都在做的事情或试图了解如何调用它们的函数)
The 'm' prefix also avoids the (IMHO) ugly and wordy "this->" notation, and the inconsistency that it guarantees (even if you are careful you'll usually end up with a mixture of 'this->data' and 'data' in the same class, because nothing enforces a consistent spelling of the name).
'm' 前缀也避免了(恕我直言)丑陋和冗长的“this->”符号,以及它保证的不一致(即使你很小心,你通常最终会混合使用 'this->data' 和'data' 在同一个类中,因为没有强制名称的拼写一致)。
'this' notation is intended to resolve ambiguity- but why would anyone deliberately write code that can be ambiguous? Ambiguity willlead to a bug sooner or later. And in some languages 'this' can't be used for static members, so you have to introduce 'special cases' in your coding style. I prefer to have a single simple coding rule that applies everywhere - explicit, unambiguous and consistent.
'this' 表示法旨在解决歧义- 但为什么有人会故意编写可能有歧义的代码?歧义迟早会导致错误。在某些语言中,“this”不能用于静态成员,因此您必须在编码风格中引入“特殊情况”。我更喜欢有一个适用于任何地方的简单编码规则——明确、明确和一致。
The last major benefit is with Intellisense and auto-completion. Try using Intellisense on a Windows Form to find an event - you have to scroll through hundreds of mysterious base class methods that you will never need to call to find the events. But if every event had an "e" prefix, they would automatically be listed in a group under "e". Thus, prefixing works to group the members, consts, events, etc in the intellisense list, making it much quicker and easier to find the names you want. (Usually, a method might have around 20-50 values (locals, params, members, consts, events) that are accessible in its scope. But after typing the prefix (I want to use an index now, so I type 'i...'), I am presented with only 2-5 auto-complete options. The 'extra typing' people attribute to prefixes and meaningful names drastically reduces the search space and measurably accelerates development speed)
最后一个主要好处是智能感知和自动完成。尝试在 Windows 窗体上使用 Intellisense 查找事件 - 您必须滚动数百个神秘的基类方法,您永远不需要调用这些方法来查找事件。但是如果每个事件都有一个“e”前缀,它们将自动列在“e”下的一个组中。因此,前缀可以对智能感知列表中的成员、常量、事件等进行分组,从而更快、更容易地找到您想要的名称。(通常,一个方法可能有大约 20-50 个值(局部变量、参数、成员、常量、事件)可以在其范围内访问。但是在输入前缀之后(我现在想使用索引,所以我输入了“i”。 ..'),我只看到 2-5 个自动完成选项。“额外输入”
I'm a lazy programmer, and the above convention saves me a lot of work. I can code faster and I make far fewer mistakes because I know how every variable should be used.
我是一个懒惰的程序员,上面的约定为我节省了很多工作。我可以更快地编码并且我犯的错误要少得多,因为我知道应该如何使用每个变量。
Arguments against
反对的论点
So, what are the cons? Typical arguments against prefixes are:
那么,有什么缺点呢?反对前缀的典型论点是:
"Prefix schemes are bad/evil". I agree that "m_lpsz" and its ilk are poorly thought out and wholly useless. That's why I'd advise using a well designed notation designed to support your requirements, rather than copying something that is inappropriate for your context. (Use the right tool for the job).
"If I change the usage of something I have to rename it". Yes, of course you do, that's what refactoring is all about, and why IDEs have refactoring tools to do this job quickly and painlessly. Even without prefixes, changing the usage of a variable almost certainly means its name oughtto be changed.
"Prefixes just confuse me". As does every tool until you learn how to use it. Once your brain has become used to the naming patterns, it will filter the information out automatically and you won't really mind that the prefixes are there any more. But you have to use a scheme like this solidly for a week or two before you'll really become "fluent". And that's when a lot of people look at old code and start to wonder how they ever managed withouta good prefix scheme.
"I can just look at the code to work this stuff out". Yes, but you don't need to waste time looking elsewhere in the code or remembering every little detail of it when the answer is right on the spot your eye is already focussed on.
(Some of) that information can be found by just waiting for a tooltip to pop up on my variable. Yes. Where supported, for some types of prefix, when your code compiles cleanly, after a wait, you can read through a description and find the information the prefix would have conveyed instantly. I feel that the prefix is a simpler, more reliable and more efficient approach.
"It's more typing". Really? One whole character more? Or is it - with IDE auto-completion tools, it will often reduce typing, because each prefix character narrows the search space significantly. Press "e" and the three events in your class pop up in intellisense. Press "c" and the five constants are listed.
"I can use
this->
instead ofm
". Well, yes, you can. But that's just a much uglier and more verbose prefix! Only it carries a far greater risk (especially in teams) because to the compiler it is optional, and therefore its usage is frequently inconsistent.m
on the other hand is brief, clear, explicit and not optional, so it's much harder to make mistakes using it.
“前缀方案是坏的/邪恶的”。我同意“m_lpsz”及其同类产品经过深思熟虑且完全没用。这就是为什么我建议使用设计良好的符号来支持您的需求,而不是复制不适合您的上下文的东西。(使用正确的工具进行工作)。
“如果我改变了某些东西的用法,我必须重命名它”。是的,你当然知道,这就是重构的全部意义,也是 IDE 具有重构工具来快速、轻松地完成这项工作的原因。即使没有前缀,改变一个变量的用法几乎肯定意味着它的名字应该被改变。
“前缀只是让我感到困惑”。就像每个工具一样,直到您学会如何使用它。一旦你的大脑习惯了命名模式,它就会自动过滤掉信息,你就不会真正介意前缀已经存在了。但是你必须坚持使用这样的方案一两个星期,才能真正变得“流利”。那时很多人看到旧代码并开始怀疑如果没有良好的前缀方案,他们是如何管理的。
“我可以看看代码来解决这个问题”。是的,但您不需要浪费时间查看代码中的其他地方或记住它的每一个小细节,当答案就在您的眼睛已经聚焦的地方时。
(一些)信息可以通过等待工具提示在我的变量上弹出来找到。是的。在支持的情况下,对于某些类型的前缀,当您的代码编译干净时,等待后,您可以通读描述并找到前缀会立即传达的信息。我觉得前缀是一种更简单、更可靠、更有效的方法。
“打字更多”。真的吗?一个完整的字符?或者是 - 使用 IDE 自动完成工具,它通常会减少输入,因为每个前缀字符都会显着缩小搜索空间。按“e”,您班级中的三个事件会在智能感知中弹出。按“c”并列出五个常数。
“我可以用
this->
代替m
”。嗯,是的,你可以。但这只是一个更丑陋、更冗长的前缀!只有它带来了更大的风险(尤其是在团队中),因为对于编译器来说它是可选的,因此它的用法经常不一致。m
另一方面是简短、清晰、明确且非可选的,因此使用它更难犯错误。
回答by jalf
I generally don't use a prefix for member variables.
我通常不为成员变量使用前缀。
I used to use a m
prefix, until someone pointed out that "C++ already has a standard prefix for member access: this->
.
我曾经使用m
前缀,直到有人指出“C++ 已经有一个用于成员访问的标准前缀:this->
.
So that's what I use now. That is, when there is ambiguity, I add the this->
prefix, but usually, no ambiguity exists, and I can just refer directly to the variable name.
所以这就是我现在使用的。即当有歧义时,我加this->
前缀,但通常情况下,不存在歧义,我可以直接引用变量名。
To me, that's the best of both worlds. I have a prefix I can use when I need it, and I'm free to leave it out whenever possible.
对我来说,这是两全其美的。我有一个前缀,我可以在需要时使用它,只要有可能,我就可以随意省略它。
Of course, the obvious counter to this is "yes, but then you can't see at a glance whether a variable is a class member or not".
当然,与此明显相反的是“是的,但是您无法一眼看出变量是否是类成员”。
To which I say "so what? If you need to know that, your class probably has too much state. Or the function is too big and complicated".
我说“那又怎样?如果你需要知道那个,你的类可能有太多的状态。或者函数太大太复杂”。
In practice, I've found that this works extremely well. As an added bonus it allows me to promote a local variable to a class member (or the other way around) easily, without having to rename it.
在实践中,我发现这非常有效。作为一个额外的好处,它允许我轻松地将局部变量提升为类成员(或其他方式),而无需重命名它。
And best of all, it is consistent! I don't have to do anything special or remember any conventions to maintain consistency.
最重要的是,它是一致的!我不需要做任何特别的事情或记住任何约定来保持一致性。
By the way, you shouldn'tuse leading underscores for your class members. You get uncomfortably close to names that are reserved by the implementation.
顺便说一句,你不应该为你的班级成员使用前导下划线。您会很不舒服地接近实现保留的名称。
The standard reserves all names starting with double underscore or underscore followed by capital letter. It also reserves all names starting with a single underscore in the global namespace.
标准保留所有以双下划线或下划线后跟大写字母开头的名称。它还保留全局命名空间中以单个下划线开头的所有名称。
So a class member with a leading underscore followed by a lower-case letter is legal, but sooner or late you're going to do the same to an identifier starting with upper-case, or otherwise break one of the above rules.
因此,带有前导下划线后跟小写字母的类成员是合法的,但迟早你会对以大写开头的标识符做同样的事情,否则就会违反上述规则之一。
So it's easier to just avoid leading underscores. Use a postfix underscore, or a m_
or just m
prefix if you want to encode scope in the variable name.
因此,避免使用前导下划线更容易。如果要在变量名称中编码范围,请使用后缀下划线或前缀m_
或仅使用m
前缀。
回答by jkeys
I prefer postfix underscores, like such:
我更喜欢后缀下划线,例如:
class Foo
{
private:
int bar_;
public:
int bar() { return bar_; }
};
回答by Grumbel
Lately I have been tending to prefer m_ prefix instead of having no prefix at all, the reasons isn't so much that its important to flag member variables, but that it avoids ambiguity, say you have code like:
最近我倾向于更喜欢 m_ 前缀而不是根本没有前缀,原因不是标记成员变量很重要,而是避免歧义,比如你有这样的代码:
void set_foo(int foo) { foo = foo; }
void set_foo(int foo) { foo = foo; }
That of cause doesn't work, only one foo
allowed. So your options are:
原因是行不通的,只foo
允许一个。所以你的选择是:
this->foo = foo;
I don't like it, as it causes parameter shadowing, you no longer can use
g++ -Wshadow
warnings, its also longer to type thenm_
. You also still run into naming conflicts between variables and functions when you have aint foo;
and aint foo();
.foo = foo_;
orfoo = arg_foo;
Been using that for a while, but it makes the argument lists ugly, documentation shouldn't have do deal with name disambiguity in the implementation. Naming conflicts between variables and functions also exist here.
m_foo = foo;
API Documentation stays clean, you don't get ambiguity between member functions and variables and its shorter to type then
this->
. Only disadvantage is that it makes POD structures ugly, but as POD structures don't suffer from the name ambiguity in the first place, one doesn't need to use it with them. Having a unique prefix also makes a few search&replace operations easier.foo_ = foo;
Most of the advantages of
m_
apply, but I reject it for aesthetic reasons, a trailing or leading underscore just makes the variable look incomplete and unbalanced.m_
just looks better. Usingm_
is also more extendable, as you can useg_
for globals ands_
for statics.
this->foo = foo;
我不喜欢它,因为它会导致参数阴影,你不能再使用
g++ -Wshadow
警告,它也不再需要输入 thenm_
。当您有 aint foo;
和 a时,您仍然会遇到变量和函数之间的命名冲突int foo();
。foo = foo_;
或者foo = arg_foo;
已经使用了一段时间,但它使参数列表变得丑陋,文档不应该处理实现中的名称歧义。这里也存在变量和函数之间的命名冲突。
m_foo = foo;
API 文档保持干净,您不会在成员函数和变量之间产生歧义,并且输入 then 更短
this->
。唯一的缺点是它使 POD 结构变得丑陋,但由于 POD 结构首先不会受到名称歧义的影响,因此不需要与它们一起使用。拥有唯一的前缀也使一些搜索和替换操作更容易。foo_ = foo;
m_
apply 的大多数优点,但出于审美原因我拒绝它,尾随或前导下划线只会使变量看起来不完整和不平衡。m_
只是看起来更好。Usingm_
也更具可扩展性,因为您可以将其g_
用于全局变量和s_
静态变量。
PS: The reason why you don't see m_
in Python or Ruby is because both languages enforce the their own prefix, Ruby uses @
for member variables and Python requires self.
.
PS:你m_
在 Python 或 Ruby中看不到的原因是因为这两种语言都强制使用自己的前缀,Ruby@
用于成员变量,而 Python 需要self.
.
回答by OldPeculier
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.
...很容易看出苹果和香蕉的来源,但葡萄、甜瓜和土豆呢?我们应该查看全局命名空间吗?在类声明中?变量是该对象的成员还是该对象类的成员?如果不知道这些问题的答案,就无法理解代码。在更长的函数中,即使是像apples 和bananas 这样的局部变量的声明也会在shuffle 中丢失。
Prepending a consistent label for globals, member variables, and static member variables (perhaps g_, m_, and s_ respectively) instantly clarifies the situation.
为全局变量、成员变量和静态成员变量(可能分别是 g_、m_ 和 s_)添加一致的标签立即澄清了这种情况。
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.)
(使用“this->”代替 m_ 是有道理的,但更冗长且视觉上具有破坏性。我不认为它是标记成员变量的所有用途的好选择。)
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 doestell 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.
匈牙利做告诉我们一些关于代码的新内容。我们现在明白在 Foo::bar() 函数中有几个隐式强制转换。现在代码的问题是,匈牙利语前缀添加的信息的价值相对于视觉成本来说很小。C++ 类型系统包括许多功能,可帮助类型协同工作或引发编译器警告或错误。编译器帮助我们处理类型——我们不需要符号来这样做。我们可以很容易地推断出 Foo::bar() 中的变量可能是数字,如果这就是我们所知道的,那对于获得对该函数的一般理解就足够了。因此知道每个变量的精确类型的价值相对较低。然而,像“s_dSpuds”(甚至只是“dSpuds”)这样的变量的丑陋是很棒的。所以,
回答by OldPeculier
I can't say how widespred it is, but speaking personally, I always (and have always) prefixed my member variables with 'm'. E.g.:
我不能说它有多么广泛,但就个人而言,我总是(并且总是)在我的成员变量前加上“m”。例如:
class Person {
....
private:
std::string mName;
};
It's the only form of prefixing I do use (I'm very anti Hungarian notation) but it has stood me in good stead over the years. As an aside, I generally detest the use of underscores in names (or anywhere else for that matter), but do make an exception for preprocessor macro names, as they are usually all uppercase.
这是我使用的唯一前缀形式(我非常反对匈牙利符号),但多年来它一直让我受益匪浅。顺便说一句,我通常讨厌在名称(或其他任何地方)中使用下划线,但对预处理器宏名称做一个例外,因为它们通常都是大写的。
回答by OldPeculier
The main reason for a member prefix is to distinguish between a member function local and a member variable with the same name. This is useful if you use getters with the name of the thing.
使用成员前缀的主要原因是为了区分局部成员函数和同名成员变量。如果您使用带有事物名称的 getter,这将很有用。
Consider:
考虑:
class person
{
public:
person(const std::string& full_name)
: full_name_(full_name)
{}
const std::string& full_name() const { return full_name_; }
private:
std::string full_name_;
};
The member variable could not be called full_name in this case. You need to rename the member function to get_full_name() or decorate the member variable somehow.
在这种情况下,成员变量不能称为 full_name。您需要将成员函数重命名为 get_full_name() 或以某种方式装饰成员变量。
回答by Dan Breslau
Some responses focus on refactoring, rather than naming conventions, as the way to improve readability. I don't feel that one can replace the other.
一些回应侧重于重构,而不是命名约定,作为提高可读性的方法。我不觉得一个可以代替另一个。
I've known programmers who are uncomfortable with using local declarations; they prefer to place all the declarations at the top of a block (as in C), so they know where to find them. I've found that, where scoping allows for it, declaring variables where they're first used decreases the time that I spend glancing backwards to find the declarations. (This is true for me even for small functions.) That makes it easier for me to understand the code I'm looking at.
我认识一些程序员,他们对使用本地声明感到不舒服;他们更喜欢将所有声明放在块的顶部(如在 C 中),因此他们知道在哪里可以找到它们。我发现,在范围允许的情况下,在首次使用变量的地方声明变量会减少我花在向后查找声明的时间。(即使对于小函数,这对我来说也是如此。)这使我更容易理解我正在查看的代码。
I hope it's clear enough how this relates to member naming conventions: When members are uniformly prefixed, I never have to look back at all; I know the declaration won't even be found in the source file.
我希望它与成员命名约定的关系足够清楚:当成员具有统一前缀时,我根本不必回头;我知道在源文件中甚至找不到该声明。
I'm sure that I didn't start out preferring these styles. Yet over time, working in environments where they were used consistently, I optimized my thinking to take advantage of them. I think it's possible that many folks who currently feel uncomfortable with them would also come to prefer them, given consistent usage.
我敢肯定,我并不是一开始就喜欢这些风格。然而,随着时间的推移,在一直使用它们的环境中工作,我优化了我的想法以利用它们。我认为鉴于一致的使用,许多目前对它们感到不舒服的人也可能会更喜欢它们。
回答by Eric
I don't think one syntax has real value over another. It all boils down, like you mentionned, to uniformity across the source files.
我不认为一种语法比另一种具有真正的价值。正如您提到的,这一切都归结为源文件的一致性。
The only point where I find such rules interesting is when I need 2 things named identicaly, for example :
我发现此类规则有趣的唯一一点是当我需要 2 个名称相同的东西时,例如:
void myFunc(int index){
this->index = index;
}
void myFunc(int index){
m_index = index;
}
I use it to differentiate the two. Also when I wrap calls, like from windows Dll, RecvPacket(...)from the Dll might be wrapped in RecvPacket(...)in my code. In these particular occasions using a prefix like "_" might make the two look alike, easy to identify which is which, but different for the compiler
我用它来区分两者。此外,当我包装调用时,例如来自 Windows Dll 的调用,来自 Dll 的RecvPacket(...)可能会包装在我的代码中的RecvPacket(...)中。在这些特殊情况下,使用像“_”这样的前缀可能会使两者看起来相似,易于识别哪个是哪个,但对于编译器来说是不同的