在类型之后命名变量是一种不好的做法吗?

时间:2010-08-28 20:42:18

标签: c++ variables naming naming-conventions

我正在使用下划线命名样式(与camel case相反)编写C ++,这也是STL和boost使用的。但是,由于类型和变量/函数都被命名为全小写,因此如下的成员变量声明将导致编译器错误(或至少是麻烦):

position position;

名为 position 的成员变量,其类型为 position 。我不知道如何命名它:它通常是一个位置,但它也是对象的位置。在驼峰的情况下,编译器可以这样做:

Position position;

但在C ++中它会导致问题。我不想切换到驼峰情况,使用匈牙利表示法或添加尾随下划线因此,所以我想知道:将类型的成员命名为类型是否是一个好习惯?

在C中,使用神秘的单字母变量是非常常见的:

int i;

但我发现有点,嗯,神秘:

position p;

我可以使用变量命名的经验法则来避免这种情况吗?

如果您需要处理某些内容,我的代码中会有更多示例:

mouse_over(entity entity) // Returns true if the mouse is over the entity

manager &manager; // A reference to the framework's manager

audio audio; // The audio subsystem

修改

我很想知道Bjarne Stroustrup本人在这个问题上是否有话要说。显然,他没有,但他建议编码约定可以解决我的编译器问题:

  

例如,大写非标准库用户定义类型并使用小写字母开始非类型

这与STL和提升是一致的,所以我可能会使用它。但是,大多数人都同意,无论是否编译,都应避免使用此命名。 Stroustrup也是如此:

  

选择仅以大小写不同的名称是不明智的。

11 个答案:

答案 0 :(得分:10)

本地意义很少是该类型的唯一全局描述:

cartesian_point_2d position;  // rectangular, not polar coordinates
mouse_over(ui_entity entity); // not a business layer entity
xyz_manager& manager;         // what's a manager without something to manage?
audio_system audio;

答案 1 :(得分:8)

赋予变量与其类型相同的名称几乎总是一个坏主意,因为它很难分辨哪些代码引用了类型以及哪些代码引用了变量。例如,请考虑以下类:

struct position
{
    void operator()() { }
};

// later on, somewhere:
position position;

现在,如果我们看到一行代码使用:

position()

我们无法判断是构造position对象还是调用position::operator()()。我们必须返回并查看当前是否存在名为position的对象。

命名约定是一个非常敏感,主观和争论的事情。我建议选择一种以某种方式区分类型和变量的方法。就个人而言,我选择将我的类型大写,并将我的变量保留为以小写字母开头。

如何区分它们(您使用大小写或尾随下划线的建议都很常见),只要您的使用是一致的。

答案 2 :(得分:3)

类型之后命名变量确实是一种不好的做法。代码应该尽可能与类型无关。这意味着对实际类型的任何引用都应限于声明(同样,尽可能多)。试图将类型信息嵌入变量名称将违反该原则。不要这样做。

人们可能想要嵌入到变量名中的是变量的语义含义。如“width”,“length”,“index”,“coordinate”,“rectangle”,“color”,“string”,“converter”等。不幸的是,许多人在看到它时错误地认为名称的这些部分旨在描述变量的类型。这种误解常常使他们在代码中稍后参与这种不良实践(在其类型之后命名变量)。

这种误解的经典着名例子是所谓的匈牙利符号。匈牙利表示法意味着在变量名称前加上特殊的统一前缀,用于描述变量的语义。在这种原始形式中,匈牙利符号是一种非常有用的良好命名惯例。但是,在许多实际情况中,它会被扭曲成完全不同的东西:在变量名前加上描述其类型的内容。后者当然不是一个好主意。

答案 3 :(得分:2)

是的,这是一种不好的做法。变量名称如果具有较长的生命周期或重要意义(临时性可以),则应该更具体。请记住,C ++是非常严格的类型 - 你不能拥有变量,也不能确定它的类型是什么。例如,变量Type类型基本上只意味着它没有名称。

答案 4 :(得分:2)

就个人而言,我将我的班级名称大写。

我不同意,“在这种特定情况下,选择仅按大写字母区分的名称是不明智的”。选择容易混淆的名字是不明智的。 PoSItIoNPoSiTIoN混淆相似。 Positionposition不是。只需确保在搜索代码时,您知道并且可以控制您是否区分大小写或不敏感。

如果我的函数只使用一个特定类型的变量,那么我可能会在类型之后命名,因为在英语中,如果有的话,“我们所讨论的唯一位置”,我们' d将其称为“位置”。因此,变量名称可以合理地为position

如果做错了,在你的例子中我可能会选择:

position pos;  // pretty sure people will realise I don't mean "positron".

mouse_over(entity target) // Returns true if the mouse is over the entity

manager &fmanager; // A reference to the framework's manager

devices::audio audio; // The audio subsystem
audio self; // "this" audio subsystem
audio audio_out; // The audio subsystem I'm configured to use for output

最后一个例子应该表明命名空间可以解决这些问题 - 在定义audio的命名空间之外,您可以安全地将其称为audio。在该命名空间内,在音频子系统上运行的函数经常是audio类接口的一部分,它恰好是自由函数(在这种情况下使用selfother,{等惯例{1}},lhs),或者是某种分层设备或系统,它将音频子系统作为依赖项(在这种情况下,依赖于什么目的?)。

顺便说一下,

rhsentity是类的可怕名称,因为它们都没有告诉你关于类代表什么的任何信息。每一个离散的东西都是一个“实体”,虽然并非所有东西都管理其他东西,但“管理”却毫无希望地模糊。

答案 5 :(得分:1)

这就是为什么我选择使用m_为成员变量添加前缀的旧MFC实践,如“m_position”。很多Java人会因为基本相同的原因而做“thePosition”,不过如果你指出他们变成有趣的颜色并对你咆哮时的相似性。

答案 6 :(得分:1)

我经常遇到同样的“问题”。我认为这是一个abstration的问题:在Position的情况下,我建议抽象一点,并引入一个类型Point或类似的东西。或者指定什么位置:

position mouse_pointer_pos;

答案 7 :(得分:0)

您可以遵循现有的指南,例如Google's C++ style guide

很高兴知道命名是一个重要的问题,但根据我的经验 过多地思考它是有害的,因为没有意识到它。

我已经尝试过匈牙利语并且不喜欢它,大多数优秀的程序员我 知道不要用它。

我要说的是它使代码的可读性降低。

答案 8 :(得分:0)

不,我有时会这样做,它不会在Microsoft世界中引起问题。例如,

class compiler
{
    symbol_table symbol_table;
};

从未引起任何混乱。顺便说一句,我称我的猫为“猫”,那也没有引起混乱。

答案 9 :(得分:0)

此命名约定imo的最大问题是,程序员不清楚表达式是引用类型还是对象。消除这种歧义的一种方法是,将代码包装在名称空间中(应如此),并使用明确的限定条件,甚至在内部使用时也是如此:

namespace my_ns {

struct audio { ... };
struct string { ... };

// Internal function whose logic doesn't require explicit qualifications.
void do_something()
{
    // Use explicit qualification nevertheless.
    my_ns::audio audio;
    audio.play("impenetrable.sd2"); // okay

    my_ns::string string;
    string.size();          // okay
    // string{}.size();     // oof, tryna re-instantiate object? compilation error
    my_ns::string{}.size(); // okay, size of just created temporary string
}

}

这很像您使用标准类型(例如std::string)的方式。由于所有用户定义的类型都将使用其名称空间进行限定,因此类型和对象之间不会存在歧义。当然,这样做的缺点是冗长:

namespace my_ns {

struct audio {
    // Using explicit qualification; pretty verbose.
    void play(my_ns::string a1, my_ns::string a2, my_ns::string a3);

    // Without explicit qualification; saves 21 characters.
    void play(string a1, string a2, string a3);
};

}

答案 10 :(得分:-1)

简短和半错误答案:如果你有足够的变量在一个地方使用,你需要非神秘的变量名,那么你可能有太多的变量。

虽然我在某种程度上实际上不同意这一点。我认为这有一定道理,但仅限于此。

C ++中的一些简短变量名称只是传统的,人们知道它们的含义,因为它们已经用C / C ++编程了一段时间。使用i作为索引变量就是一个例子。

我认为应该根据其目的命名变量名称。这个位置的立场是什么?经理在管理什么?为什么音频子系统的这个特定实例需要存在?

尾随_表示法用于区分成员变量名称。当有人开始提到x无处可见x_并知道它来自类时,并且未在封闭范围或全局范围内声明时,它会非常有用。