Это хорошая идея «#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)
  • Когда вы рефакторизируете код и делаете функцию, не являющуюся членом, явным образом (для улучшения инкапсуляции), это показывает вам место, которое вы должны отредактировать, и вы можете легко заменить его указателем на экземпляр класса, заданного как параметр функции, не являющейся членом
  • Как правило, когда вы меняете код, вероятность появления ошибок больше, если вы не используете явное это, чем когда вы используете явное это везде.
  • Явное, это менее шумно, чем явное «m_», когда вы обращаетесь к члену извне ( object.memberпротив object.m_member) (благодаря @Kaz, чтобы определить этот момент)
  • Явно это решает проблему универсально для всех членов - атрибутов и методов, тогда как «m_» или другой префикс практически применим только для атрибутов.

Я хотел бы отточить и расширить этот список, сообщить мне, если вы знаете о других преимуществах, и использовать варианты для явного повсюду .


3
Вы должны избегать использования аргументов функций и членов с одинаковыми именами, а также избегать явного «this».
pjc50

4
Напоминает мне код VB моего босса. Me Me Me везде. Звучит эгоистично. : p В любом случае, ответы пока говорят все это.
MetalMikester

19
Это прекрасная идея! А для тех, кто пришел из Python, почему бы и нет #define self (*this)? Вы можете даже смешивать оба макроса и иметь некоторые файлы, имитирующие VB и другие Python. :)
logc

11
Почему бы не просто идти на все, и делать: #include "vb.h", #Include pascal.h, или #include FOTRAN.hи иметь следующие человек потрогать ваш код передать его TDWTF .
Дэн Нили

4
О, пожалуйста, просто нет. Вы можете избежать некоторых проблем, просто объявив атрибуты как me_x.
Gort the Robot

Ответы:


90

Нет это не так.

Имейте в виду программиста, который будет поддерживать ваш код через несколько лет после того, как вы отправитесь на более зеленые пастбища, и следовать общим правилам языка, который вы используете. В C ++ вам почти никогда не придется писать this, потому что класс включается в порядке разрешения символов, и когда символ находится в области видимости класса, this->это подразумевается. Так что просто не пиши, как все.

Если вы часто путаетесь, какие символы приходят из области видимости класса, обычный подход заключается в использовании общего шаблона именования для членов (полей и иногда частных методов; я не видел, чтобы они использовались для открытых методов). Общие включают суффикс с _или префикс с m_или m.


12
«В C ++ вам почти никогда не придется писать это» , это совершенно не связанное с этим соглашение. Некоторые люди (например, я) предпочитают писать, thisчтобы ясно дать понять, что переменная не является локальной для метода. Вопрос здесь в том, meдолжен ли существовать макрос , а не в том, thisчто следует использовать.
Мердад

8
@Mehrdad: Потому что ОП явно говорит, что он использует me.вместо this->. Поскольку в этом нет необходимости this->, нет необходимости me.и, следовательно, нет необходимости в макросе.
Мартин Йорк,

11
@LokiAstari: Ничто в этом вопросе даже намекает на то, что ОП интересуется, this->«необходимо ли». Фактически, ОП говорит, что он использует, this->несмотря на то, что в этом нет необходимости. Вопрос в том, me.следует ли использовать вместо этого this-> , на который этот ответ фактически не отвечает.
Мердад

4
@Mehrdad: Но только положительный ответ да или нет дает очень скучный ответ. Таким образом, объяснения, как правило, весьма полезны при объяснении того, как достигается ответ (кодируется как ответить ). Вывод не для использования, потому что OP имеет неправильное отношение для начала об использовании thisи, следовательно, обсуждение этого вопроса необходимо для достижения полностью сбалансированного заключения.
Мартин Йорк,

1
+1 за объяснение, почему вместо того, чтобы просто сказать «Нет, это плохая практика».
user253751 15.07.14

42

Итак, вы хотите создать новый язык. Тогда сделайте так, и не наносите вред C ++.

Есть несколько причин не делать этого:

  1. Каждый нормальный стандарт кодирования предлагает избегать макросов ( вот почему )
  2. С такими макросами сложнее поддерживать код. Каждый, кто программирует на C ++, знает, что thisесть, и, добавляя такой макрос, вы фактически добавляете новое ключевое слово. Что, если каждый представит то, что им нравится? Как будет выглядеть код?
  3. Вы не должны использовать (*this).или this->вообще, за исключением некоторых особых случаев (см. Этот ответ и поиск "this->")

Ваш код не отличается от того #define R return, который я видел в реальном коде. Причина? Меньше печатать!


Слегка не по теме, но здесь я собираюсь остановиться на пункте 3 (не использовать (*this).или this->в классе).

Прежде всего, (*this).или this->используются для доступа к переменным-членам или функциям объекта. Использовать его бессмысленно и значит больше печатать. Кроме того, читать такой код сложнее, потому что там больше текста. Это означает более сложное обслуживание.

Итак, в каких случаях вы должны использовать this->?

(а) неудачный выбор имени аргумента.

В этом примере this->требуется, поскольку аргумент имеет то же имя, что и переменная-член:

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

(б) При работе с шаблонами и наследования (см. это )

Этот пример не удастся скомпилировать, потому что компилятор не знает, к какой переменной 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 ++ является их гибкость. OP не наносит вреда C ++, а просто использует его гибкость особым образом, чтобы ему было легче кодировать.
user253751 15.07.14

2
@immibis Верно. Что легче для него, тем труднее для всех остальных. Когда вы работаете в команде, внесение подобной чепухи в кодекс не сделает вас очень выгодным.
BЈовић

2
Ваш ответ не отличается от «определяет зло».
Мистер Листер

7
@MrLister Мой ответ "глупо определяет зло". Макрос в вопросе глупый для использования и, как я показал, совсем не нужен. Код хороший и даже лучше без *this.иthis->
BЈовић

1
@ Mehrdad Люди все еще добавляют префиксы и суффиксы к переменным-членам? Я думал, что это было "исправлено" с книгами вроде Чистого кода . this->так же полезно, как и autoв pre-c ++ 11. Другими словами, это только увеличивает шум кода.
BЈовић

26

Я предлагаю не делать этого. Это дает читателю, который не знаком с вашим макросом большой " WTF » всякий раз, когда он видит это. Код не становится более читабельным при изобретении «новых соглашений» по сравнению с общепринятыми без какой-либо реальной необходимости.

используя это-> везде слишком шумно и некрасиво

Это может показаться вам таким, может быть, потому что вы много программировали на языках, используя ключевое слово me(Visual Basic, я полагаю?). Но на самом деле это просто вопрос привыкания к нему - this->довольно короткий, и я думаю, что большинство опытных программистов на C ++ не согласятся с вашим мнением. А в вышеприведенном случае ни использование, this->ни использование не meявляются подходящими - вы получаете наименьшее количество помех, оставляя эти ключевые слова при доступе к элементам данных внутри функций-членов.

Если вы хотите, чтобы ваши закрытые переменные-члены отличались от локальных, добавьте к ним ссылку m_в качестве префикса или подчеркивание в качестве суффикса к ним (но, как вы можете видеть здесь , даже это соглашение «слишком шумно» для многих людей).


12
_должен иметь суффикс ; в качестве префикса он зарезервирован для внутренних символов стандартных библиотек и расширений поставщиков.
Ян Худек

4
@JanHudec Только если оно начинается с __(два подчеркивания) или подчеркивания, за которым следует заглавная буква. Одное подчеркивание, за которым следует строчная буква, подойдет, если только оно не находится в глобальном пространстве имен.
Эрик Финн

1
@EricFinn: я объединил два правила в одно. Два подчеркивания или подчеркивания, за которыми следует заглавная буква, предназначены для внутренних символов, а одно подчеркивание, за которым следует строчная буква, предназначено для системных расширений. Приложения не должны использовать либо.
Ян Худек

@JanHudec Не знал о правиле для системных расширений. Я оставлю свой предыдущий комментарий, чтобы обеспечить некоторый контекст для вашего комментария.
Эрик Финн

2
@JanHudec: Нижний регистр предназначен для системных расширений? Не могли бы вы опубликовать ссылку на часть стандарта C ++, которая указывает на это?
Мердад

18

Пожалуйста, не делай этого! Я пытаюсь справиться с большой базой кода, где макросы повсюду, чтобы сохранить типизацию. Плохая вещь при переопределении этого для меня заключается в том, что препроцессор заменит его везде, даже если это не входит в область действия / не применяется, например, в качестве отдельной функции, у вашего коллеги может быть локальная переменная, называемая мной где-то еще .. (s) он не будет доволен отладкой ... В итоге у вас будут макросы, которые вы не сможете использовать во всех областях.


6

НЕТ!

Просто представьте себе путаницу, которая произойдет, если кто-то # включит этот заголовок, не зная вашего трюка, и в других местах своего файла у него есть переменная или функция, называемая "я". Они будут ужасно смущены тем непостижимым сообщением об ошибке, которое будет напечатано.


На практике они вполне могут навести курсор мыши на «меня» своей IDE и увидеть определение.
user253751

2
@immibis: На практике, они также могут сказать что-то вроде «кто написал это дерьмо?». : P
cHao

@immibis: большинство топ-кодеров, с которыми я работаю, не используют мышь - это слишком медленно.
Дж.Б. Уилкинсон

Действительно: засунуть это в заголовок - актуальная проблема. Если вы используете его в своем файле cpp, я не вижу проблемы вообще. Если бы у нас был стандартный прагма, я бы посоветовал, как сделать это в заголовке, но мы этого не сделаем. Повторяй за мной. # определения являются глобальными.
Джошуа
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.