Це гарна ідея "#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"
  • Коли ви видаляєте або перейменовуєте якогось члена, компілятор надійно повідомляє вас у місцях, де цей член використовується. (Деякі глобальні функції можуть мати одне ім’я та існувати ймовірність, що ви можете ввести помилку, якщо ви не використовуєте явне це).
  • Коли ви рефакторинг коду і робить не члена члена функції від члена (щоб зробити кращу інкапсуляцію) явним, це показує вам місце, яке ви повинні відредагувати, і ви можете легко замінити це покажчиком на екземпляр класу, який задається як параметр функції не члена
  • Як правило, коли ви змінюєте код, є більше шансів на помилки, коли ви не використовуєте явне це, ніж коли ви явно це використовуєте скрізь.
  • Відверто, це менш шумно, ніж явне „m_“, коли ви вступаєте до складу ( object.memberз object.m_member) (завдяки @Kaz, що помітив цю точку)
  • Явне це вирішує універсальну проблему для всіх членів - атрибути та методи, тоді як „m_“ або інший префікс практично можна використовувати лише для атрибутів.

Я хотів би відполірувати і розширити цей список, скажіть, якщо ви знаєте про інші переваги та використовуєте випадки для явного цього скрізь .


3
Вам слід уникати наявності аргументів функцій та членів з однаковою назвою, а також уникати явного "цього".
pjc50

4
Нагадує про код VB мого начальника. Мене Мене всюди. Звучить егоїстично. : 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
"У С ++ вам майже ніколи не доводиться писати цього" , це абсолютно не пов'язане з умовою питання. Деякі люди (як я) вважають за краще писати, thisщоб явно дати зрозуміти, що змінна не є локальною для методу. Тут виникає питання про те, чи meповинен існувати макрос , а не чи thisварто використовувати щось.
Мехрдад

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

11
@LokiAstari: Ніщо в питанні навіть віддалено не натякає на ОП, цікаво, this->"чи потрібно". Насправді ОП каже, що він використовує, this->незважаючи на те, що це не потрібно. Питання в тому, чи me.слід використовувати замість цього this-> , на що ця відповідь насправді не відповідає.
Мехрдад

4
@Mehrdad: Але тільки надати так чи ні, це дуже нудна відповідь. Таким чином, пояснення, як правило, є досить корисними для пояснення того, як відповідь досягається (це викликає роздратування, як відповісти ). Висновок не використовувати, оскільки ОП має неправильне ставлення до початку використання, thisі тому необхідна дискусія з цього питання для досягнення повністю збалансованого висновку.
Мартін Йорк

1
+1, щоб пояснити, чому замість того, щоб просто сказати "Ні, це погана практика".
користувач253751

42

Отже, ви хочете створити нову мову. Потім зробіть це, і не калічить C ++.

Є кілька причин цього не робити:

  1. Кожен звичайний стандарт кодування пропонує уникати макросів ( ось чому )
  2. З такими макросами важче підтримувати код. Усі, хто програмує на C ++, знають, що thisтаке, і додаючи такий макрос, ви фактично додаєте нове ключове слово. Що робити, якщо кожен представить щось, що їм подобається? Як би виглядав код?
  3. Ви не повинні використовувати (*this).або this->взагалі, крім деяких особливих випадків (див. Цю відповідь та шукайте "це->")

Ваш код не відрізняється від того #define R return, який я бачив у фактичному коді. Причина? Менше набирайте текст!


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

Перш за все, (*this).або this->використовуються для доступу до змінних або функцій об'єкта. Використовувати його безглуздо і означає більше вводити текст. Крім того, читати такий код складніше, тому що там більше тексту. Це означає складніше обслуговування.

Отже, які випадки, коли вам доведеться користуватися this->?

(а) Невдалий вибір назви аргументу.

У цьому прикладі 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 ++ є їх гнучкість. ОП не калічить C ++, просто використовує його гнучкість певним чином, щоб полегшити йому чи її кодування.
користувач253751

2
@immibis Правильно. Що йому легше, тим важче для всіх інших. Коли ви працюєте в команді, внесення таких дурниць у код не зробить вас дуже сприятливим.
BЈовић

2
Ваша відповідь не відрізняється від "визначає зло".
Містер Лістер

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

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

26

Я пропоную цього не робити. Це дає читачеві, який не знайомий з вашим макросом, великий " WTF ", коли він бачить це. Кодекс не стає більш читабельним, коли вигадують "нові конвенції" над загальноприйнятими без будь-якої реальної потреби.

використання цього-> скрізь занадто шумно і некрасиво

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

Якщо ви хочете, щоб ваші змінні приватного члена відрізнялися від локальних, додайте щось посилання m_як префікс або підкреслення як суфікс (але, як ви бачите тут , навіть ця умова є "занадто галасливою" для багатьох людей).


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

4
@JanHudec Тільки якщо він починається з __(два підкреслення) або підкреслення, за яким йде велика літера. Єдине підкреслення, що супроводжується малою літерою, добре, доки його немає у глобальному просторі імен.
Ерік Фінн

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

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

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

18

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


6

НІ!

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


На практиці вони, швидше за все, переходять на "мене" зі своєю IDE і бачать визначення.
користувач253751

2
@immibis: На практиці, однак, вони також можуть сказати щось на кшталт "хто написав це лайно?". : P
cHao

@immibis: більшість найпопулярніших кодерів, з якими я працюю, не використовують мишу - це занадто повільно.
JBRWilkinson

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