为什么在 C++ 类中的数据成员上使用像 m_ 这样的前缀?

2024-05-10

许多 C++ 代码使用语法约定来标记数据成员。常见的例子包括

  • m_memberName对于公共成员(在所有使用公共成员的情况下)
  • _memberName对于私人会员或所有会员

其他人尝试强制使用this->member每当使用数据成员时。

根据我的经验,大多数较大的代码库都无法一致地应用这些规则。

在其他语言中,这些约定远没有那么普遍。我只是偶尔在 Java 或 C# 代码中看到它。我想我从未在 Ruby 或 Python 代码中见过它。因此,更现代的语言似乎有一种趋势,即不对数据成员使用特殊标记。

这个约定现在在 C++ 中仍然有用吗?或者它只是一个不合时宜的东西,特别是因为它在各个库中的使用如此不一致?难道其他语言没有表明可以不用成员前缀吗?


我完全赞成前缀做得很好.

我认为(系统)匈牙利表示法是造成前缀的大部分“坏名声”的原因。

这种表示法在强类型语言中基本上没有意义,例如在 C++ 中“lpsz”告诉你你的字符串是一个指向 nul 终止字符串的长指针,当: 分段架构是古老的历史,C++ 字符串按照常见约定是指向 nul 终止 char 数组的指针,而且这并不是那么困难要知道“customerName”是一个字符串!

但是,我确实使用前缀来指定usage变量(本质上是“Apps Hungarian”,尽管我更喜欢避免使用“Hungarian”一词,因为它与“System Hungarian”有不好且不公平的关联),这是一个非常方便的节省时间 and 减少错误方法。

I use:

  • m 会员
  • c 用于常量/只读
  • p 代表指针(pp 代表指向指针的指针)
  • v 表示易失性
  • s 代表静态
  • i 用于索引和迭代器
  • e 代表事件

我希望在哪里做type显然,我使用标准后缀(例如列表、组合框等)。

这让程序员意识到usage每当他们看到/使用变量时。可以说,最重要的情况是指针的“p”(因为用法从 var. 变为 var->,并且您必须更加小心地使用指针 - NULL、指针算术等),但所有其他情况都非常方便。

例如,您可以在单个函数中以多种方式使用相同的变量名:(这里是 C++ 示例,但它同样适用于许多语言)

MyClass::MyClass(int numItems)
{
    mNumItems = numItems;
    for (int iItem = 0; iItem < mNumItems; iItem++)
    {
        Item *pItem = new Item();
        itemList[iItem] = pItem;
    }
}

你可以在这里看到:

  • 成员和参数之间不会混淆
  • 索引/迭代器和项目之间不会混淆
  • 使用一组明确相关的变量(项目列表、指针和索引),避免通用(模糊)名称(如“计数”、“索引”)的许多陷阱。
  • 与“itemIndex”和“itemPtr”等替代方案相比,前缀可以减少输入(更短,并且可以更好地自动完成)

“iName”迭代器的另一个优点是,我永远不会使用错误的索引来索引数组,并且如果我将一个循环复制到另一个循环中,我不必重构其中一个循环索引变量。

比较一下这个不切实际的简单例子:

for (int i = 0; i < 100; i++)
    for (int j = 0; j < 5; j++)
        list[i].score += other[j].score;

(这很难阅读,并且经常导致在本来应该是“j”的地方使用“i”)

with:

for (int iCompany = 0; iCompany < numCompanies; iCompany++)
    for (int iUser = 0; iUser < numUsers; iUser++)
       companyList[iCompany].score += userList[iUser].score;

(这更具可读性,并且消除了索引方面的所有混乱。通过现代 IDE 中的自动完成功能,这也可以快速且轻松地键入)

下一个好处是代码片段不需要任何上下文被理解。我可以将两行代码复制到电子邮件或文档中,任何阅读该代码片段的人都可以区分所有成员、常量、指针、索引等之间的区别。我不必添加“哦,要小心,因为‘data’是一个指向指针的指针”,因为它被称为‘ppData’。

出于同样的原因,我不必将目光从一行代码上移开就能理解它。我不必搜索代码来查找“data”是否是本地、参数、成员或常量。我不必将手移到鼠标上,这样我就可以将指针悬停在“数据”上,然后等待工具提示(有时永远不会出现)弹出。这样程序员就可以阅读并理解代码显著地更快,因为他们不会浪费时间上下搜索或等待。

(如果您认为自己不浪费时间上下搜索来解决问题,请找到一些您一年前编写但尚未查看的代码 自从。打开文件并跳到一半而不阅读它。 在你不知道是否可以之前,看看你能从这一点读到多远 某物是成员、参数或本地。现在跳转到另一个随机 位置...这就是我们单身时整天所做的事情 单步执行别人的代码或尝试了解如何 调用它们的函数)

'm' 前缀还避免了(恕我直言)丑陋且冗长的“this->”表示法,以及它所保证的不一致(即使你很小心,你通常会得到 'this->data' 和'data' 在同一个类中,因为没有任何东西强制名称的拼写一致)。

“this”符号旨在解决歧义- 但为什么有人会故意编写可能不明确的代码呢?歧义will迟早会导致错误。在某些语言中,“this”不能用于静态成员,因此您必须在编码风格中引入“特殊情况”。我更喜欢有一个简单的、适用于任何地方的编码规则——明确、明确和一致。

最后一个主要好处是智能感知和自动完成。尝试在 Windows 窗体上使用 Intellisense 来查找事件 - 您必须滚动浏览数百个神秘的基类方法,而您永远不需要调用这些方法来查找事件。但如果每个事件都有“e”前缀,它们将自动列在“e”下的组中。因此,前缀可以对智能感知列表中的成员、常量、事件等进行分组,从而更快、更轻松地找到所需的名称。 (通常,一个方法可能有大约 20-50 个可在其范围内访问的值(局部变量、参数、成员、常量、事件)。但是在输入前缀后(我现在想使用索引,所以我输入 'i. ..'),我只看到 2-5 个自动完成选项。人们归因于前缀和有意义的名称的“额外输入”大大减少了搜索空间并显着加快了开发速度)

我是一个懒惰的程序员,上面的约定为我节省了很多工作。我可以更快地编码,并且犯的错误也少得多,因为我知道应该如何使用每个变量。


反对的论点

那么,有什么缺点呢?反对前缀的典型论点是:

  • “前缀方案是坏/邪恶的”。我同意“m_lpsz”及其类似内容经过深思熟虑且完全无用。这就是为什么我建议使用精心设计的符号来支持您的需求,而不是复制不适合您的上下文的内容。 (使用适合工作的正确工具)。

  • “如果我改变某个东西的用途,我就必须重命名它”。是的,当然可以,这就是重构的意义所在,也是为什么 IDE 拥有重构工具来快速、轻松地完成这项工作。即使没有前缀,更改变量的用法几乎肯定意味着它的名称ought被改变。

  • “前缀让我很困惑”。就像每个工具一样,直到您学会如何使用它为止。一旦你的大脑习惯了命名模式,它就会自动过滤掉信息,你就不会介意前缀的存在了。但你必须扎实地使用这样的方案一两周,然后你才能真正变得“流利”。就在那时,很多人查看旧代码并开始想知道他们是如何管理的without一个好的前缀方案。

  • “我只需查看代码即可解决这个问题”。是的,但是当答案就在您眼睛已经关注的地方时,您不需要浪费时间查看代码中的其他位置或记住代码的每个小细节。

  • (部分)信息只需等待工具提示在我的变量上弹出即可找到。是的。在支持的情况下,对于某些类型的前缀,当您的代码干净编译后,等待一段时间后,您可以通读描述并立即找到该前缀将传达的信息。我觉得前缀是一种更简单、更可靠、更高效的方法。

  • “打字多了”。真的吗?多一个完整的角色?或者是 - 使用 IDE 自动完成工具,通常会减少输入,因为每个前缀字符都会显着缩小搜索空间。按“e”,您班级中的三个事件会在智能感知中弹出。按“c”,会列出五个常数。

  • “我可以用this->代替m"。嗯,是的,你可以。但这只是一个更丑陋、更冗长的前缀!只是它带来了更大的风险(尤其是在团队中),因为对于编译器来说optional,因此它的用法经常不一致。m另一方面,它是简短、清晰、明确且非可选的,因此使用它更难犯错误。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在 C++ 类中的数据成员上使用像 m_ 这样的前缀? 的相关文章

  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • std::list 线程push_back、front、pop_front

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • C++ 中的参考文献

    我偶尔会在 StackOverflow 上看到代码 询问一些涉及函数的重载歧义 例如 void foo int param 我的问题是 为什么会出现这种情况 或者更确切地说 你什么时候会有 对参考的参考 这与普通的旧参考有何不同 我从未在现
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使

随机推荐