“ #define me(* this)”是个好主意吗?


19

可以在某些全局头文件中或更佳地将其定义为编译器命令行参数:

#define me (*this)

还有一些用法示例:

some_header.h:

inline void Update()
{
    /* ... */
}

main.cpp:

#include "some_header.h"

class A {
public:
    void SetX(int x)
    {
        me.x = x;   
        me.Update(); 
    }

    void SomeOtherFunction()
    {
        ::Update();
    }

    /*
        100 or more lines
        ... 
    */

    void Update()
    {
        // ... 
    }

    int x;  
};

因此,在类方法中,当我访问类成员时,我总是使用me,而在访问全局标识符时,我总是使用::。这为读者提供了对代码不熟悉的信息(可能是几个月后的我自己),无需访问其他地方即可获得所访问内容的本地化信息。我想进行定义,me因为我发现this->到处使用都过于嘈杂和丑陋。但是可以#define me (*this)认为是C ++的良好实践吗?me宏是否存在一些实用的问题点?而且,如果您作为C ++程序员将是使用该me宏的某些代码的读者,您是否愿意?

编辑:因为很多人争论不具体反对使用me,而是一般反对明确这一点。我认为可能尚不清楚“在任何地方都可以利用”的好处。

“到处都利用”的好处是什么?

  • 作为代码阅读者,您可以确定所访问的内容,并且可以专心于不同的事情,而不必验证-在某些遥远的代码中-确实可以访问您认为可以访问的内容。
  • 您可以更具体地使用搜索功能。搜索“ this->x”可以为您提供更多搜索结果,而不是仅搜索“ x
  • 当您删除或重命名某些成员时,编译器会在使用该成员的位置可靠地通知您。(某些全局函数可以具有相同的名称,并且如果不使用显式的函数,可能会引入错误)。
  • 当您重构代码并从成员中明确非成员函数(以更好地封装)时,这会显示您必须编辑的位置,并且可以轻松地将其替换为指向作为非成员函数参数给出的类的实例的指针
  • 通常,当您更改代码时,不使用显式this的错误可能性要比在各处使用显式this的可能性更大。
  • 当您从外部(object.membervs object.m_member)访问成员时,显式此方法比显式的“ m_”要少(多谢@Kaz指出这一点)
  • 明确地说,这解决了所有成员(属性和方法)的普遍性问题,而“ m_”或其他前缀实际上仅可用于属性。

我想完善和扩展此列表,告诉我您是否了解其他优势,并在所有地方都明确使用此示例


3
您应该避免具有相同名称的函数参数和成员,以及避免显式的“ this”。
pjc50

4
让我想起了老板的VB代码。我我到处都是我。听起来很自私。:p无论如何,到目前为止的答案都说明了一切。
MetalMikester 2014年

19
这是一个好主意!对于那些有Python背景的人,为什么不#define self (*this)呢?您甚至可以混合使用两个宏,并拥有一些模仿VB的文件和其他模仿Python的文件。:)
logc

11
为什么不全力以赴,然后做:#include "vb.h"#Include pascal.h#include FOTRAN.h让下一个碰您代码的人将其提交给TDWTF
Dan Neely 2014年

4
哦,拜托,只是没有。您只需将属性声明为,就可以避免麻烦me_x
Gort机器人2014年

Answers:


90

不它不是。

请注意,从现在起,您将离开绿色的牧场,并遵循所用语言的通用约定,很长一段时间后就会维护您的代码的程序员。在C ++中,几乎不需要写this,因为该类按符号解析顺序包含,this->并且隐含了在类范围内找到符号的隐含含义。因此,请不要像其他人那样编写它。

如果您经常混淆哪些符号来自类范围,那么通常的方法是为成员使用通用命名模式(字段,有时是私有方法;我还没有看到它用于公共方法)。常见的包括与后面添加_或前缀m_m


12
“在C ++中,您几乎不必编写此代码”与该问题完全无关。有些人(像我一样)更喜欢写代码,this以明确表明变量不是方法的局部变量。这里的问题是关于宏是否me应该存在,而不是是否this应该使用某些宏。
Mehrdad 2014年

8
@Mehrdad:因为OP明确表示他正在使用me.而不是this->。由于this->不需要me.,因此也不需要宏。
马丁·约克

11
@LokiAstari:问题中甚至没有任何暗示暗示OP怀疑this->“是否必要”。实际上,OP表示this->尽管没有必要,他仍在使用。问题是,是否me.应使用而不是 this->,该答案实际上并没有回答。
Mehrdad 2014年

4
@Mehrdad:但是只说是或否是一个很无聊的答案。因此,在解释如何达到答案(由“ 如何回答”来确定)时,通常使用解释是非常有用的。该结论不可用,因为OP的使用态度从错误开始,this因此需要对这一点进行讨论才能得出完全平衡的结论。
马丁·约克

1
+1解释原因,而不仅仅是说“不,这是一种不良做法”。
user253751

42

因此,您想创建一种新的语言。然后这样做,不要削弱C ++。

不这样做的原因有很多:

  1. 每个正常的编码标准都会建议避免使用宏(这就是原因
  2. 使用此类宏维护代码更加困难。用C ++进行编程的每个人都知道是什么this,通过添加这样的宏,实际上是在添加一个新关键字。如果每个人都介绍自己喜欢的东西怎么办?代码是什么样的?
  3. 除了在某些特殊情况下,您不应该使用(*this).或根本不使用this->(请参阅此答案并搜索“ this->”)

您的代码#define R return与实际代码中的没什么不同。原因?少打字!


略微偏离主题,但在这里我将扩展第3点(不要使用(*this).this->在类中)。

首先,(*this).还是this->用于访问对象的成员变量或函数。使用它是没有意义的,意味着更多的输入。另外,由于存在更多文本,因此读取此类代码更加困难。这意味着难以维护。

那么,在什么情况下您必须使用this->

(a)不幸选择了论据名称。

在此示例中,this->由于参数的名称与成员变量的名称相同,所以是必需的:

struct A {
  int v;
  void foo( int v ) {
    this->v =v;
  }
};

(b)当使用模板和继承处理(见

该示例将无法编译,因为编译器不知道v要访问哪个变量。

template< typename T >
struct A {
  A(const T& vValue):v(vValue){}

  T v;
};

template< typename T >
struct B : A<T>
{
    B(const T& vValue):A<T>(vValue){}

    void foo( const T & newV ) {
      v = newV;
    }
};

1
“因此,您想创建一种新的语言。然后这样做,并且不要削弱c ++。” - 我不同意。C和C ++的主要优势是它们的灵活性。OP不会削弱C ++,只是以一种特殊的方式利用其灵活性,使他(她)更容易编写代码。
user253751

2
@immibis对。对他来说更容易,对其他人则更难。当您在团队中工作时,在代码中添加这些废话不会使您非常满意。
BЈовић

2
您的答案与“定义是邪恶的”没有什么不同。
李斯特先生,2014年

7
@MrLister我的回答是“愚蠢的定义是邪恶的”。问题中的宏使用起来很愚蠢,而且正如我所展示的,根本不需要。该代码是好,甚至更好,而不*this.this->
BЈовић

1
@Mehrdad人们还在向成员变量添加前缀和后缀吗?我以为这是用Clean Code之类的书“解决”的。与c ++ 11之前的版本this->一样有用auto。换句话说,它只会增加代码噪声。
BЈовић

26

我建议不要这样做。这给不熟悉您的宏的读者每当看到一个大的“ WTF ”。在没有任何实际需要的情况下,在普遍接受的约定之上发明“新约定”时,代码的可读性不会更高。

在所有地方都使用this->太嘈杂和丑陋

在您看来,这可能是因为您使用关键字me(我猜是Visual Basic)用语言进行了大量编程。但是实际上,这只是习惯它的问题- this->很短,我想大多数有经验的C ++程序员都会不同意您的意见。在上述情况下,使用this->或使用me都不适合-在访问成员函数内部的数据成员时,通过将那些关键字排除在外,可以使混乱程度最小。

如果希望将私有成员变量与本地变量区分开,m_它们的前缀上添加链接或在其后缀中添加下划线(但正如您在此处看到的那样,即使这样的约定对很多人来说也“太吵”了)。


12
_应该加后缀 ; 作为前缀,它保留用于标准库和供应商扩展的内部符号。
Jan Hudec

4
@JanHudec仅当以__(两个下划线)或下划线后跟一个大写字母开头时。只要不在下一个全局名称空间中,就可以在单个下划线后加上小写字母。
埃里克·芬

1
@EricFinn:我将这两个规则合二为一。两个下划线或下划线后跟大写字母表示内部符号,单个下划线后跟小写字母表示系统特定的扩展名。应用程序均不应使用。
Jan Hudec 2014年

@JanHudec不了解系统特定扩展的规则。不过,我将保留先前的评论,以便为您的评论提供一些背景信息。
埃里克·芬

2
@JanHudec:小写用于系统特定的扩展吗?您能否发布对C ++标准中表明这一点的部分的引用?
Mehrdad 2014年

18

请不要这样做!我正在尝试处理庞大的代码库,其中到处都是宏,以节省键入内容。对我重新定义的不好的事情是,即使在范围之外/不适用的情况下,预处理器也将在任何地方替换它,例如,一个独立的函数,您的同事可能在其他地方有一个叫做我的局部变量。 。(s)他将不乐于调试...您最终将拥有不能在所有范围内使用的宏。


6

没有!

试想一下,如果有人#include是那个标头,却不知道您的把戏,而在他们文件的其他地方,它们有一个称为“ me”的变量或函数,那将会造成混乱。他们将被打印出任何难以理解的错误消息所困扰。


在实践中,他们很可能将IDE上的“ me”鼠标悬停在上面,并查看其定义。
user253751

2
@immibis:尽管在实践中,他们也可能会说“谁写了这个废话?”之类的话。:P
cHao 2014年

@immibis:与我合作的大多数顶级编码器都不使用鼠标-太慢了。
JBR威尔金森2014年

确实:将其推入标题是实际的问题。如果在cpp文件中使用它,我根本看不到任何问题。如果我们将杂注推送作为标准操作,我会建议如何在页眉中执行此操作,但我们不建议这样做。在我之后重复。#define是全局的。
约书亚
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.