这个问题在这里已经有答案了:

我正在处理一个大型代码库,该代码库始终使用以下构造

class MyClass
{
public:
  void f(int x);
private:
  int x;
};


void MyClass::f(int x)
{
'
'
  this->x = x;
'
'
}

就我个人而言,我一直使用并因此更喜欢这种形式

class MyClass
{
public:
  void f(int x);
private:
  int _x;
};


void MyClass::f(int x)
{
'
'
  _x = x;
'
'
}

我更喜欢后者的原因是它更简洁(更少的代码=更少的潜在错误),并且我不喜欢在范围内同时存在多个同名变量,这样我就可以避免它。也就是说,这些天我越来越频繁地看到前一种用法。我不知道第二种方法有什么好处吗?(例如。对编译时间的影响、与模板化代码一起使用等...)这两种方法的优点是否足够显着,值得重构另一种方法?我问的原因是,虽然我不喜欢代码中存在的第二种方法,但引入更多错误的工作量和相关风险并不值得重构。

有帮助吗?

解决方案

你的版本有点干净,但是当你这样做时,我会:

  1. 避免前导下划线:_x 是可以的,直到有人选择 _MyField(这是一个保留名称)。不允许将首字母下划线后跟大写字母作为变量名。看: 在 C++ 标识符中使用下划线的规则是什么?
  2. 将属性设置为私有或受保护:如果可以编译,则更改是安全的,并且您将确保您的设置器将被使用。
  3. this-> 故事有一个用途,例如在模板化代码中使字段名称依赖于您的类型(可以解决一些查找问题)。

名称解析的一个小示例,通过使用显式 this-> 进行修复(使用 g++ 3.4.3 进行测试):

#include <iostream>
#include <ostream>

class A
{
public:
  int g_;
  A() : g_(1) {}
  const char* f() { return __FUNCTION__; }
};

const char* f() { return __FUNCTION__; }
int g_ = -1;

template < typename Base >
struct Derived : public Base
{
  void print_conflicts()
  {
    std::cout << f() << std::endl; // Calls ::f()
    std::cout << this->f() << std::endl; // Calls A::f()
    std::cout << g_ << std::endl; // Prints global g_
    std::cout << this->g_ << std::endl; // Prints A::g_
  }
};

int main(int argc, char* argv[])
{
   Derived< A >().print_conflicts();
   return EXIT_SUCCESS;
}

其他提示

字段命名与代码味道无关。作为 尼尔 也就是说,字段可见性是这里唯一的代码味道。

有很多关于 C++ 命名约定的文章:

ETC。

Microsoft C# 编码标准鼓励使用“this”。它提供了良好的代码清晰度,并且旨在成为成员变量中使用 m_ 或 _ 或任何其他内容的标准。

老实说,无论如何,我真的不喜欢名称中的下划线,我曾经在所有成员前面加上一个“m”前缀。

很多人使用它是因为在他们的 IDE 中它会弹出当前类的标识符列表。

我知道我在 BCB 就是这么做的。

我认为您提供的命名冲突示例是一个例外。但在 Delphi 中,样式指南使用参数前缀(通常是“a”)来避免这种情况。

我个人的感觉是,与现有的编码约定相冲突是你不应该做的事情。正如 Sutter/Alexandrescu 在他们的《C++ 编码约定》一书中所说:不要为小事而烦恼。任何人都可以读取其中一个,无论是否有前导的“this->”或“_”或其他任何内容。

然而,命名约定的一致性是您通常想要的,因此在某个范围(至少是文件范围,当然最好是整个代码库)坚持一种约定被认为是一种很好的做法。您提到这种风格在更大的代码库中使用,所以我认为改造另一个约定将是一个坏主意。

毕竟,如果您发现有充分的理由进行更改,请不要手动执行此操作。在最好的情况下,您的 IDE 支持此类“重构”。否则,编写一个脚本来更改它。搜索和替换应该是最后一个选项。无论如何,您应该有一个备份(源代码控制)和某种自动化测试工具。否则你不会从中得到乐趣。

在我看来,以这种方式使用“this”并不是代码味道,而只是个人喜好。因此,它并不像与系统中其余代码的一致性那么重要。如果此代码不一致,您可以更改它以匹配其他代码。如果通过更改它会导致与其余大部分代码不一致,那是非常糟糕的,我不会管它。

你不想陷入这样一种情况:有人纯粹为了让它看起来“漂亮”而改变一些东西,只是为了让其他人后来有不同的品味,然后又把它改回来。

我总是使用 米_ 命名约定。虽然我总体上不喜欢“匈牙利表示法”,但我发现如果我正在处理类成员数据,那么清楚地看到它非常有用。另外,我发现在同一范围内使用 2 个相同的变量名太容易出错。

我同意。我不喜欢这种命名约定 - 我更喜欢成员变量和局部变量之间有明显区别的命名约定。如果您忽略会发生什么 this?


class MyClass{
public:  
  int x;  
  void f(int xval);
};
//
void MyClass::f(int xval){  
  x = xval;
}

在我看来 往往会给代码带来混乱,所以我倾向于使用不同的变量名称(根据约定,它可能是下划线, 米_, , 任何)。

class MyClass
{
public:
  int m_x;
  void f(int p_x);
};


void MyClass::f(int p_x)
{
  m_x = p_x;
}

...是我使用范围前缀的首选方式。m_ 表示成员,p_ 表示参数(有些使用 a_ 表示参数),g_ 表示全局,有时 l_ 表示局部(如果有助于可读性)。

如果您有两个具有相同名称的变量,那么这会很有帮助,并且避免为了避免重新定义而必须对其含义进行一些随机变化。或者更糟糕的是,可怕的“x2、x3、x4 等”......

在 C++ 中,使用初始化器在构造时初始化成员是更正常的。

为此,您必须使用与成员变量名称不同的名称。

所以即使我会用 Foo(int x) { this.x = x; } 在 Java 中,我不会在 C++ 中。

真正的味道可能是缺乏使用初始化程序和方法,它们除了改变成员变量之外什么也不做,而不是使用 this -> x 本身。

有人知道为什么在我去过的每个 C++ 商店中,在与初始化程序一起使用时,对成员变量的构造函数参数使用不同的名称是普遍做法吗?是否有一些 C++ 编译器不支持它?

如今,大多数 IDE 编辑器都会对变量进行着色以指示局部变量的类成员。因此,IMO,为了可读性,不需要前缀或“this->”。

我不喜欢使用“this”,因为它是返祖现象。如果您使用古老的 C 进行编程(还记得 C 吗?),并且想要模仿 OOP 的一些特征,您可以创建一个包含多个成员的结构体(这些成员类似于对象的属性),然后创建一个集合所有函数都将指向该结构的指针作为其第一个参数(这些函数类似于该对象的方法)。

(我认为这个 typedef 语法是正确的,但已经有一段时间了......)

typedef struct _myclass
{
   int _x;
} MyClass;

void f(MyClass this, int x)
{
   this->_x = x;
}

事实上,我相信较旧的 C++ 编译器实际上会将您的代码编译为上述形式,然后将其传递给 C 编译器。换句话说,C++ 在某种程度上只是语法糖。所以我不确定为什么有人会想用 C++ 编程并返回到在代码中显式使用“this”——也许这是“语法 Nutrisweet”

如果您对命名约定有疑问,可以尝试使用如下内容。

class tea
{
public:
    int cup;
    int spoon;
    tea(int cups, int spoons);
};

或者

class tea
{
public:
    int cup;
    int spoon;
    tea(int drink, int sugar);
};

我想你明白了。它基本上是对变量进行不同的命名,但在逻辑意义上是“相同的”。我希望它有帮助。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top