Подтвердить что ты не робот

Чрезмерное использование `this` в С++

Я имею дело с большой базой кода, которая использует следующую конструкцию в

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;
'
'
}

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

4b9b3361

Ответ 1

Ваша версия немного чище, но пока вы на ней, я бы:

  • Избегайте подчеркивания: _x нормально, пока кто-то не выберет _MyField, который является зарезервированным именем. Начальное подчеркивание, за которым следует заглавная буква, не допускается как имя переменной. Смотрите: Каковы правила использования подчеркивания в идентификаторе С++?
  • Сделать атрибут закрытым или защищенным: изменение безопасно, если оно компилируется, и вы убедитесь, что ваш сеттер будет использоваться.
  • История 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;
}

Ответ 2

Именование полей не имеет никакого отношения к коду. Как сказал Neil, видимость поля является единственным кодом здесь.

В С++ существуют различные статьи относительно соглашений об именах:

и др.

Ответ 3

Это использование 'this' поощряется стандартами кодирования Microsoft С#. Он дает хорошую четкость кода и предназначен для использования в качестве стандартного использования m_ или _ или чего-либо еще в переменных-членах.

Честно говоря, мне все равно не нравится подчеркивание в именах, я использовал для префикса всех моих членов одним "м".

Ответ 4

Многие люди используют это, потому что в своей среде IDE он отобразит список идентификаторов текущего класса.

Я знаю, что я делаю в BCB.

Я думаю, что пример, который вы предоставляете с конфликтом имен, является исключением. Однако в Delphi правила стиля используют префикс (обычно "a" ) для параметров, чтобы избежать этого.

Ответ 5

Мое личное чувство заключается в том, что борьба с существующим соглашением о кодировании - это то, что вы не должны делать. Как Sutter/Alexandrescu помещает его в свою книгу "Соглашения о кодировании на С++": не потейте мелкие вещи. Любой может читать тот или иной, есть ли ведущий "this- > " или "_" или что-то еще.

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

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

Ответ 6

Используя 'this' таким образом, IMO не является запахом кода, а просто личным предпочтением. Поэтому это не так важно, как согласованность с остальной частью кода в системе. Если этот код несовместим, вы можете изменить его в соответствии с другим кодом. Если, изменив его, вы введете несогласованность с большинством остальной части кода, это очень плохо, и я оставил бы его в покое.

Вы не хотите когда-либо вступать в игру, играя в кодовый теннис, где кто-то что-то меняет, чтобы заставить его выглядеть "красивым" только для того, чтобы кто-то другой пришел позже с разными вкусами, которые затем меняют его.

Ответ 7

Я всегда использую соглашение об именах m _. Хотя мне не нравится "венгерская нотация" в целом, мне очень полезно видеть очень четко, если я работаю с данными о членах класса. Кроме того, я обнаружил, что использование двух идентичных имен переменных в той же области слишком подвержено ошибкам.

Ответ 8


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

Ответ 9

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

Ответ 10

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

Ответ 11

Это более нормально в С++ для того, чтобы члены были инициализированы при построении с использованием инициализатора.

Для этого вам нужно использовать другое имя для имени переменной-члена.

Итак, хотя я использовал бы Foo(int x) { this.x = x; } в Java, я бы не стал на С++.

Реальным запахом может быть отсутствие использования инициализаторов и методов, которые ничего не делают, кроме мутирующих переменных-членов, а не использования самого this -> x.

Забастовкa >

Кто-нибудь знает, почему это универсальная практика в каждом магазине С++, в котором я работал, использовать разные имена для аргументов конструктора для переменных-членов при использовании с инициализаторами? были ли некоторые компиляторы С++, которые его не поддерживали?

Ответ 12

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 и т.д."...

Ответ 13

Сегодня большинство редакторов IDE окрашивают ваши переменные для указания членов класса локальных переменных. Таким образом, IMO, ни префиксы, ни "this- > " не требуется для удобочитаемости.

Ответ 14

Мне не нравится использовать "this", потому что он атавистический. Если вы программируете в добром старом C (помните C?), И хотите подражать некоторым характеристикам ООП, вы создаете структуру с несколькими членами (они аналогичны свойствам вашего объекта), и вы создаете набор функций, которые все принимают указатель на эту структуру как свой первый аргумент (они аналогичны методам этого объекта).

(Я думаю, что этот синтаксис typedef верен, но это было некоторое время...)

typedef struct _myclass
{
   int _x;
} MyClass;

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

На самом деле я считаю, что старшие компиляторы С++ фактически скомпилировали ваш код в вышеуказанную форму, а затем просто передали его компилятору C. Другими словами - С++ в какой-то степени был просто синтаксическим сахаром. Поэтому я не уверен, почему кто-то хочет запрограммировать на С++ и вернуться к явному использованию "this" в коде - возможно, это "синтаксический Nutrisweet"

Ответ 15

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

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

или

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

Думаю, у тебя есть идея. Он в основном называет переменные разные, но "одинаковые" в логическом смысле. Надеюсь, это поможет.