Po co używać prefiksów na zmiennych członkowskich w klasach C++

Wiele kodu C++ używa konwencji składniowych do oznaczania zmiennych członkowskich. Typowe przykłady to

  • m_ memberName for public members (where public members are used at all)
  • _nazwa użytkownika dla członków prywatnych lub wszystkich członków

Inni próbują wymusić używając tego - > member za każdym razem, gdy używana jest zmienna member.

Z mojego doświadczenia wynika, że większość większych baz kodu nie stosuje takich reguł konsekwentnie.

W innych językach konwencje te są znacznie mniej rozpowszechnione. Widzę to tylko sporadycznie w kodzie Java lub C#. Myślę, że nigdy nie widziałem go w kodzie Ruby lub Python. Tak więc, wydaje się, że istnieje tendencja w bardziej nowoczesnych językach, aby nie używać specjalnych znaczników dla zmiennych członkowskich.

Czy ta konwencja jest nadal przydatna w C++, czy jest to po prostu anachronizm. Zwłaszcza, że jest on używany tak niekonsekwentnie w bibliotekach. Czy inne języki nie wykazały, że można zrobić bez prefiksów członków?

Author: VoidPointer, 2009-08-04

29 answers

Musisz być ostrożny z używaniem głównego podkreślenia. Główny podkreślnik przed wielką literą w słowie jest zarezerwowany. Na przykład:

_Foo

_L

Są wszystkie słowa zastrzeżone podczas

_foo

_l

Nie są. Istnieją inne sytuacje, w których nie wolno rozpoczynać podkreślenia przed małymi literami. W moim konkretnym przypadku okazało się, że _l jest zarezerwowany przez Visual C++ 2005 i The clash stworzył nieoczekiwane wyniki.

Jestem na ogrodzeniu o tym, jak przydatne jest oznaczanie zmiennych lokalnych.

Oto link o którym identyfikatory są zastrzeżone: jakie są zasady używania podkreślenia w identyfikatorze C++?

 50
Author: Juan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:21

Jestem za przedrostki zrobione dobrze .

Myślę, że (System) Węgierski notacja jest odpowiedzialny za większość "zły rap", że prefiksy dostać.

Ta notacja jest w dużej mierze bezcelowa w silnie typowanych językach, np. w C++ "lpsz", aby powiedzieć ci, że Twój łańcuch znaków jest długim wskaźnikiem do łańcucha zakończonego znakiem nul, kiedy: segmentowana architektura jest starożytną historią, łańcuchy C++ są przez wspólną konwencję wskaźnikami do tablic znaków zakończonych znakiem nul i nie jest to naprawdę trudne wiedzieć, że "customerName" to ciąg znaków!

Jednak używam prefiksów, aby określić użycie zmiennej (zasadniczo "apps Hungarian" , chociaż wolę unikać określenia Hungarian ze względu na złe i niesprawiedliwe skojarzenie z systemem Hungarian), i jest to bardzo przydatne podejście timesavingi bug-reduction.

Używam:

  • M dla członków
  • c dla stałych / readonlys
  • p dla wskaźnika (i pp dla wskaźnika do wskaźnik)
  • v dla lotnych
  • S dla statycznych
  • i dla indeksów i iteratorów
  • e Dla wydarzeń

Gdzie chcę, aby Typ był jasny, używam standardowych przyrostków (np. List, ComboBox, itp.).

To uświadamia programiście użycie zmiennej, gdy tylko ją zobaczy/użyje. Prawdopodobnie najważniejszym przypadkiem jest" p " dla wskaźnika (ponieważ użycie zmienia się z var. do var- > i trzeba być o wiele bardziej ostrożnym z pointers-NULLs, pointer arytmetyka, etc), ale wszystkie inne są bardzo przydatne.

Na przykład, możesz użyć tej samej nazwy zmiennej na wiele sposobów w jednej funkcji: (tutaj przykład C++, ale dotyczy to jednakowo wielu języków)

MyClass::MyClass(int numItems)
{
    mNumItems = numItems;
    for (int iItem = 0; iItem < mNumItems; iItem++)
    {
        Item *pItem = new Item();
        itemList[iItem] = pItem;
    }
}

Możesz zobaczyć tutaj:

  • brak pomylenia członu z parametrem
  • brak pomyłek pomiędzy indeksem / iteratorem a pozycjami
  • użycie zestawu wyraźnie powiązanych zmiennych (lista pozycji, wskaźnik i indeks), które unikają wiele pułapek nazw rodzajowych (niejasnych), takich jak "count", "index".
  • Przedrostki zmniejszają typowanie (krótsze i działają lepiej z autouzupełnianiem) niż alternatywy takie jak" itemIndex "i"itemPtr" [26]}

Kolejnym świetnym punktem iteratorów "iName" jest to, że nigdy nie indeksuję tablicy z niewłaściwym indeksem, a jeśli kopiuję pętlę wewnątrz innej pętli, nie muszę refaktorować jednej ze zmiennych indeksujących pętlę.

Porównaj ten nierealistycznie prosty przykład:

for (int i = 0; i < 100; i++)
    for (int j = 0; j < 5; j++)
        list[i].score += other[j].score;

(co jest trudne do czytane i często prowadzi do użycia "i", gdzie" j " było przeznaczone)

Z:

for (int iCompany = 0; iCompany < numCompanies; iCompany++)
    for (int iUser = 0; iUser < numUsers; iUser++)
       companyList[iCompany].score += userList[iUser].score;

(który jest znacznie bardziej czytelny i usuwa wszelkie zamieszanie związane z indeksowaniem. Dzięki automatycznemu uzupełnianiu w nowoczesnych IDE jest to również szybkie i łatwe do wpisania)

Kolejną korzyścią jest to, że fragmenty kodu nie wymagają zrozumienia żadnego kontekstu. Mogę skopiować dwa wiersze kodu do wiadomości e-mail lub dokumentu, a każdy, kto czyta ten fragment, może odróżnić wszystkie elementy, stałe, wskaźniki, indeksy itp. Nie muszę dodawać "och, i bądź ostrożny, ponieważ 'data' jest wskaźnikiem do wskaźnika", ponieważ nazywa się 'ppData'.

I z tego samego powodu, nie muszę przesuwać oczu poza linię kodu, aby ją zrozumieć. Nie muszę przeszukiwać kodu, aby znaleźć, czy 'data' jest lokalnym, parametrem, członkiem lub stałą. Nie muszę przesuwać ręki na mysz, więc mogę najechać kursorem na "dane", a następnie czekać na podpowiedź (która czasami nigdy się nie pojawia), aby wyskakuj. Tak więc programiści mogą czytać i rozumieć kod znacznie szybciej, ponieważ nie tracą czasu na szukanie w górę iw dół lub czekanie.

(Jeśli uważasz, że nie tracisz czasu na szukanie w górę iw dół, aby popracować nad tym, znajdź jakiś kod, który napisałeś rok temu i nie zaglądałeś do niego od tamtej pory. Otwórz plik i przeskocz w połowie bez czytania go. Zobacz jak daleko możesz od tego momentu czytać zanim nie wiesz czy coś jest członkiem, parametrem lub lokalnym. Teraz przejdź do innego losowego miejsce... To jest to, co robimy przez cały dzień, kiedy jesteśmy samotni przechodzenie przez cudzy kod lub próba zrozumienia, jak wywołanie ich funkcji)

Przedrostek " m " unika również (IMHO) brzydkiej i wyrazistej notacji "this ->" i niespójności, którą gwarantuje (nawet jeśli jesteś ostrożny, Zwykle skończysz z mieszaniną "this - > data" i "data" w tej samej klasie, ponieważ nic nie wymusza spójnej pisowni danych nazwisko).

' ta ' notacja ma na celu rozwiązanie niejednoznaczności - ale dlaczego ktoś celowo pisze kod, który może być niejednoznaczny? Niejednoznaczność prędzej czy później doprowadzi do błędu. W niektórych językach' this ' nie może być używane dla statycznych członków, więc musisz wprowadzić 'specjalne przypadki' w swoim stylu kodowania. Wolę mieć jedną prostą zasadę kodowania, która obowiązuje wszędzie-wyraźną, jednoznaczną i spójną.

[[6]}ostatnią główną korzyścią jest Intellisense i autouzupełnianie. Spróbuj użyć Intellisense w formularzu Windows, aby znaleźć Zdarzenie - musisz przewijać setki tajemniczych metod klasy podstawowej, których nigdy nie będziesz musiał wywoływać, aby znaleźć zdarzenia. Ale jeśli każde zdarzenie miało przedrostek "e", automatycznie zostałoby wymienione w grupie pod"e". Tak więc prefiks działa na grupowanie członków, konst, wydarzeń itp. na liście intellisense, dzięki czemu znacznie szybciej i łatwiej jest znaleźć pożądane nazwy. (Zazwyczaj metoda może mieć około 20-50 wartości (miejscowi, paramy, członkowie, const, wydarzenia), które są dostępne w jego zakresie. Ale po wpisaniu prefiksu (chcę teraz użyć indeksu, więc wpisuję 'i..."), Mam tylko 2-5 opcji auto-complete. "Extra typing" ludzie przypisują do przedrostków i znaczących nazw drastycznie zmniejsza przestrzeń wyszukiwania i wymiernie przyspiesza szybkość rozwoju)

Jestem leniwym programistą, a powyższa konwencja oszczędza mi dużo pracy. Potrafię kodować szybciej i popełniam dużo mniej błędów ponieważ Wiem, jak każda zmienna powinna być używana.


Argumenty przeciw

Jakie są wady? Typowe argumenty przeciw przedrostkom to:
  • "Schematy prefiksów są złe/złe" . Zgadzam się, że "m_lpsz" i jego podobizna są słabo przemyślane i zupełnie bezużyteczne. Dlatego radzę używać dobrze zaprojektowanej notacji zaprojektowanej, aby wspierać twoje wymagania, zamiast kopiować coś, co jest nieodpowiednie dla Twojego kontekstu. (Użyj odpowiedniego narzędzia do pracy).

  • "jeśli zmienię użycie czegoś, muszę zmienić jego nazwę" . Tak, oczywiście, że tak, na tym polega refaktoryzacja i dlaczego IDE mają narzędzia do refaktoryzacji, aby wykonać tę pracę szybko i bezboleśnie. Nawet bez prefiksów, zmiana użycia zmiennej prawie na pewno oznacza, że jej nazwa powinna zostać zmieniona.

  • "przedrostki po prostu mnie mylą" . Jak każde narzędzie, dopóki nie nauczysz się go używać. Gdy twój mózg ma przyzwyczajaj się do wzorców nazewnictwa, automatycznie odfiltruje informacje i nie będziesz miał nic przeciwko temu, że prefiksy są już tam. Ale musisz używać takiego schematu solidnie przez tydzień lub dwa, zanim naprawdę staniesz się "biegły". I wtedy wiele osób patrzy na stary kod i zaczyna się zastanawiać, jak udało im się kiedykolwiek Bez dobrego schematu prefiksów.

  • "mogę po prostu spojrzeć na kod, aby to rozwiązać" . Tak, ale nie potrzebujesz tracić czas na szukanie w innym miejscu kodu lub zapamiętywanie każdego jego najmniejszego szczegółu, gdy odpowiedź znajduje się w miejscu, na którym twoje oko jest już skupione.

  • (niektóre z tych informacji można znaleźć po prostu czekając na podpowiedź, która pojawi się na mojej zmiennej . Tak. Tam, gdzie obsługiwane, dla niektórych rodzajów prefiksów, gdy kod kompiluje się czysto, po odczekaniu, można przeczytać opis i znaleźć informacje, które prefiks byłby przekazany natychmiast. Czuję, że prefiks jest prostszym, bardziej niezawodnym i bardziej wydajnym podejściem.

  • "to bardziej typowanie" . Naprawdę? Jedna postać więcej? A może jest - dzięki narzędziom autouzupełniania IDE często zmniejsza to typowanie, ponieważ każdy znak przedrostka znacznie zawęża przestrzeń wyszukiwania. Naciśnij "e", a trzy wydarzenia w twojej klasie pojawią się w intellisense. Naciśnij " c " i pięć stałych są wymienione.

  • "mogę użyć this-> zamiast m". Możesz. Ale to jest po prostu dużo brzydszy i bardziej wyrazisty przedrostek! Tylko, że niesie ze sobą znacznie większe ryzyko (szczególnie w zespołach), ponieważ dla kompilatora jest to opcjonalne, a zatem jego użycie jest często niespójne. m z drugiej strony jest krótki, jasny, wyraźny i nie opcjonalny, więc znacznie trudniej jest popełnić błędy przy jego użyciu.

 240
Author: Jason Williams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-27 12:36:57

Generalnie nie używam prefiksu dla zmiennych członkowskich.

Używałem prefiksu m, dopóki ktoś nie zauważył, że " C++ ma już standardowy prefiks dostępu dla członków: this->.

Więc tego używam teraz. Oznacza to, że gdy istnieje niejednoznaczność , dodaję przedrostek this->, ale zazwyczaj nie ma niejednoznaczności i mogę po prostu odnieść się bezpośrednio do nazwy zmiennej. Dla mnie to najlepsze z obu światów. Mam prefiks, którego mogę używać, gdy tego potrzebuję i jestem wolny zostaw to w miarę możliwości.

Oczywiście oczywistym przeciwnikiem tego jest "tak, ale wtedy nie widać na pierwszy rzut oka, czy zmienna jest członkiem klasy, czy nie".

Do którego mówię "i co z tego? Jeśli chcesz to wiedzieć, twoja klasa pewnie ma za dużo stanu. Albo funkcja jest zbyt duża i skomplikowana".

W praktyce okazało się, że to działa bardzo dobrze. Jako dodatkowy bonus pozwala mi łatwo promować zmienną lokalną dla członka klasy (lub na odwrót) , bez konieczności zmiany nazwy.

A co najlepsze, to jest spójne! Nie muszę robić niczego specjalnego ani pamiętać żadnych konwencji, aby zachować spójność.


Przy okazji, ty nie powinieneś używać znaków podkreślenia dla członków twojej klasy. Masz nieprzyjemnie bliskie nazwy, które są zarezerwowane przez implementację.

Standard zastrzega wszystkie Nazwy zaczynające się od podwójnego podkreślenia lub podkreślenia, po którym następuje wielka litera. Zastrzega również wszystkie nazwy począwszy od pojedynczego podkreślenia w globalnej przestrzeni nazw .

Więc członek klasy z głównym podkreśleniem, po którym następuje mała litera jest legalny, ale prędzej czy później zrobisz to samo z identyfikatorem zaczynającym się od wielkich liter, lub w inny sposób złamiesz jedną z powyższych reguł.

Więc łatwiej jest po prostu uniknąć podkreślenia. Użyj podkreślenia postfixa lub prefiksu m_ lub po prostu m, jeśli chcesz zakodować zakres w nazwie zmiennej.

 116
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 17:01:30

Ja wolę Postfix, jak taki:

class Foo
{
   private:
      int bar_;

   public:
      int bar() { return bar_; }
};
 34
Author: jkeys,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 16:46:27

Ostatnio miałem tendencję do preferowania prefiksu m_ zamiast nie mieć prefiksu w ogóle, powody nie są tak ważne, aby oznaczać zmienne członkowskie, ale aby uniknąć niejednoznaczności, powiedzmy, że masz kod w stylu: {21]}

void set_foo(int foo) { foo = foo; }

Przyczyna nie działa, dozwolone jest tylko jedno foo. Więc twoje opcje to:

  • this->foo = foo;

    Nie podoba mi się to, ponieważ powoduje cieniowanie parametrów, nie można już używać ostrzeżeń g++ -Wshadow, jest również dłuższe do wpisania wtedy m_. Ty również nadal występują konflikty nazw między zmiennymi i funkcjami, gdy masz int foo; i int foo();.

  • foo = foo_; lub foo = arg_foo;

    Używam tego od jakiegoś czasu, ale to sprawia, że listy argumentów są brzydkie, dokumentacja nie powinna mieć do czynienia z dwuznacznością nazw w implementacji. Istnieją tu również konflikty nazw między zmiennymi i funkcjami.

  • m_foo = foo;

    Dokumentacja API pozostaje czysta, nie można uzyskać niejednoznaczności między funkcjami członkowskimi i zmiennych oraz jego krótsze do wpisania wtedy this->. Jedyną wadą jest to, że sprawia, że struktury POD są brzydkie, ale ponieważ struktury POD nie cierpią z powodu niejednoznaczności nazwy, nie trzeba jej używać z nimi. Unikalny prefiks ułatwia również kilka operacji wyszukiwania i zastępowania.

  • foo_ = foo;

    Stosuje się większość zalet m_, ale odrzucam to ze względów estetycznych, końcówka lub główny podkreślenie sprawia, że zmienna wygląda niekompletnie i niezrównoważony. Po prostu wygląda lepiej. Użycie m_ jest również bardziej rozszerzalne, ponieważ można użyć {[15] } dla globali i s_ dla statyki.

PS: powodem, dla którego nie widzisz m_ w Pythonie lub Rubim jest to, że oba języki wymuszają swój własny prefiks, Ruby używa {[18] } dla zmiennych członkowskich, a Python wymaga self..

 22
Author: Grumbel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-22 13:34:57

Podczas odczytywania funkcji member, wiedza, kto "jest właścicielem" każdej zmiennej jest absolutnie niezbędna do zrozumienia jej znaczenia. W funkcji takiej jak Ta:

void Foo::bar( int apples )
{
    int bananas = apples + grapes;
    melons = grapes * bananas;
    spuds += melons;
}

...łatwo jest zobaczyć, skąd pochodzą jabłka i banany, ale co z winogronami, melonami i spudami? Powinniśmy zajrzeć do globalnej przestrzeni nazw? W deklaracji klasowej? Czy zmienna jest członkiem tego obiektu czy członkiem klasy tego obiektu? Nie znając odpowiedzi na te pytania, można nie rozumiem kodu. A w dłuższej funkcji nawet deklaracje zmiennych lokalnych, takich jak jabłka i banany, mogą zgubić się w tasowaniu.

Przygotowanie spójnej etykiety dla globali, zmiennych członkowskich i statycznych zmiennych członkowskich (być może odpowiednio g_, m_ i s_) natychmiast wyjaśnia sytuację.

void Foo::bar( int apples )
{
    int bananas = apples + g_grapes;
    m_melons = g_grapes * bananas;
    s_spuds += m_melons;
}

To może wymagać trochę przyzwyczajenia na początku-ale potem, co w programowaniu nie? Był taki dzień, kiedy nawet wyglądał dziwnie dla Ciebie. A kiedy już się przyzwyczaisz dla nich pomagają znacznie szybciej zrozumieć kod.

(Użycie "this - >" zamiast m_ ma sens, ale jest jeszcze bardziej długotrwałe i wizualnie uciążliwe. Nie uważam tego za dobrą alternatywę dla oznaczania wszystkich zastosowań zmiennych członkowskich.)

Ewentualnym sprzeciwem wobec powyższego argumentu byłoby rozszerzenie argumentu na typy. Może być również prawdą, że znajomość typu zmiennej " jest absolutnie niezbędna do zrozumienia znaczenia zmiennej."Jeśli tak, to dlaczego nie dodajesz prefiksu do każdej nazwy zmiennej, która identyfikuje jej typ? Z tą logiką kończy się Węgierska notacja. Ale wielu ludzi uważa węgierską notację za pracochłonną, brzydką i nieprzydatną.

void Foo::bar( int iApples )
{
    int iBananas = iApples + g_fGrapes;
    m_fMelons = g_fGrapes * iBananas;
    s_dSpuds += m_fMelons;
}

Węgierski mówi nam coś nowego o kodzie. Teraz rozumiemy, że w funkcji Foo::bar() jest kilka ukrytych odlewów. Problem z kodem polega teraz na tym, że wartość informacji dodawanych przez prefiksy węgierskie jest niewielka w stosunku do kosztów wizualnych. C++ system typów zawiera wiele funkcji, które pomagają typom albo dobrze ze sobą współpracować, albo zgłaszać Ostrzeżenie kompilatora lub błąd. Kompilator pomaga nam radzić sobie z typami-nie potrzebujemy do tego notacji. Możemy łatwo wywnioskować, że zmienne w foo::bar() są prawdopodobnie liczbowe i jeśli to wszystko, co wiemy, jest to wystarczająco dobre, aby uzyskać ogólne zrozumienie funkcji. Dlatego wartość znajomości dokładnego typu każdej zmiennej jest stosunkowo niska. Jednak brzydota zmiennej typu " s_dSpuds" (lub nawet po prostu "dSpuds") jest świetny. Tak więc analiza kosztów i korzyści odrzuca notację węgierską, podczas gdy korzyści z g_, s_ i m_ przytłaczają koszty w oczach wielu programistów.

 12
Author: OldPeculier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-21 18:00:49

Nie mogę powiedzieć, jak szeroka jest, ale mówiąc osobiście, zawsze (i zawsze) poprzedzałem moje zmienne członkowskie 'm'. Np.:

class Person {
   .... 
   private:
       std::string mName;
};

Jest to jedyna forma prefiksu, której używam (jestem bardzo anty węgierską notacją), ale stała mi na dobre przez lata. Na marginesie, generalnie nie znoszę używania podkreślników w nazwach (lub gdziekolwiek indziej), ale robię wyjątek dla nazw makr preprocesora, ponieważ zwykle wszystkie są wielkimi literami.

 10
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 15:30:36

Głównym powodem prefiksu członka jest rozróżnienie między funkcją członka lokalną a zmienną członka o tej samej nazwie. Jest to przydatne, jeśli używasz getterów z nazwą rzeczy.

Rozważmy:

class person
{
public:
    person(const std::string& full_name)
        : full_name_(full_name)
    {}

    const std::string& full_name() const { return full_name_; }
private:
    std::string full_name_;
};

Zmienna Członkowska nie może być w tym przypadku wywołana jako full_name. Musisz zmienić nazwę funkcji członka na get_full_name () lub udekorować zmienną członka w jakiś sposób.

 8
Author: Wolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-01 10:28:47

Myślę, że jedna składnia nie ma rzeczywistej wartości nad inną. Wszystko sprowadza się, jak wspomniałeś, do jednolitości w plikach źródłowych.

Jedyny punkt, w którym uważam takie zasady za interesujące, to Kiedy potrzebuję 2 rzeczy o identycznej nazwie, na przykład:

void myFunc(int index){
  this->index = index;
}

void myFunc(int index){
  m_index = index;
}

Używam go do rozróżniania tych dwóch. Również gdy zawijam wywołania, jak z Windows Dll, RecvPacket(...) z Dll może być zawinięty w RecvPacket(...) w moim kodzie. W tych szczególnych przypadkach przy użyciu prefiks taki jak "_" może sprawić, że oba te elementy będą podobne, łatwe do zidentyfikowania, które jest Które, ale inne dla kompilatora

 6
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 15:33:13

Niektóre odpowiedzi koncentrują się na refaktoryzacji, a nie konwencjach nazewniczych, jako sposobie na poprawę czytelności. Nie czuję, że jedno może zastąpić drugie.

Znam programistów, którzy nie lubią używać lokalnych deklaracji; wolą umieszczać wszystkie deklaracje na górze bloku (jak w C), więc wiedzą, gdzie je znaleźć. Odkryłem, że tam, gdzie pozwala na to scoping, deklarowanie zmiennych, w których są używane po raz pierwszy, zmniejsza czas, który spędzam patrząc wstecz na znajdź deklaracje. (Dotyczy to mnie nawet w przypadku małych funkcji.) To ułatwia mi zrozumienie kodu, na który patrzę.

Mam nadzieję, że jest wystarczająco jasne, w jaki sposób odnosi się to do konwencji nazewnictwa członków: gdy członkowie są jednolicie poprzedzeni, nigdy nie muszę patrzeć wstecz; wiem, że deklaracja nie zostanie nawet znaleziona w pliku źródłowym.

Jestem pewien, że nie zacząłem preferować tych stylów. Jednak z czasem praca w środowiskach, w których były konsekwentnie wykorzystywane, Zoptymalizowałem swoje myślenie, aby je wykorzystać. Myślę, że jest możliwe, że wielu ludzi, którzy obecnie czują się z nimi nieswojo, również przyjdzie je preferować, biorąc pod uwagę spójne użycie.

 6
Author: Dan Breslau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 18:42:36

Te konwencje to tylko to. Większość sklepów używa konwencji kodu, aby ułatwić czytelność kodu, dzięki czemu każdy może łatwo spojrzeć na fragment kodu i szybko rozszyfrować między rzeczami, takimi jak członkowie publiczni i prywatni.

 5
Author: Mr. Will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 15:31:51

Inni próbują wymusić użycie this - > member zmienna jest używana

Jest to zwykle , ponieważ nie ma przedrostka . Kompilator potrzebuje wystarczającej ilości informacji, aby rozwiązać daną zmienną, niezależnie od tego, czy jest to unikalna nazwa ze względu na prefiks, czy za pomocą słowa kluczowego this.

Więc tak, myślę, że prefiksy są nadal przydatne. Ja, na przykład, wolałbym wpisać'_', aby uzyskać dostęp do członka, a nie ' this ->'.

 5
Author: Kent Boogaart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-27 15:26:51

Inne języki będą używać konwencji kodowania, po prostu wydają się być różne. Na przykład C# ma prawdopodobnie dwa różne style, których ludzie używają, albo jedną z metod C++ (_variable, mVariable lub inny prefiks, taki jak notacja węgierska), albo to, co nazywam metodą StyleCop.

private int privateMember;
public int PublicMember;

public int Function(int parameter)
{
  // StyleCop enforces using this. for class members.
  this.privateMember = parameter;
}
W końcu staje się tym, co ludzie wiedzą i co wygląda najlepiej. Osobiście uważam, że kod jest bardziej czytelny bez Węgierskiej notacji, ale może stać się łatwiej znaleźć zmienną z intellisense na przykład, jeśli dołączona jest notacja węgierska.

W moim przykładzie powyżej, nie potrzebujesz prefiksu m dla zmiennych członkowskich, ponieważ prefiks użycia z tym. wskazuje to samo w metodzie wymuszonej przez kompilator.

To nie musi oznaczać, że inne metody są złe, ludzie trzymają się tego, co działa.
 4
Author: Will Eddins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 15:33:53

Gdy masz duże metody lub bloki kodu, wygodnie jest natychmiast wiedzieć, czy używasz zmiennej lokalnej lub elementu. to jest, aby uniknąć błędów i dla lepszej przejrzystości !

 3
Author: Matthieu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 15:33:00

IMO, to sprawa osobista. Nie umieszczam żadnych prefiksów. W każdym razie, jeśli kod ma być publiczny, myślę, że powinien mieć kilka prefiksów, więc może być bardziej czytelny.

Często duże firmy używają własnych tak zwanych "reguł programistycznych".
Btw, najzabawniejszy a zarazem najmądrzejszy jaki widziałem to DRY KISS (Dont Repeat Yourself. Keep It Simple, Stupid). :-)

 3
Author: Andrejs Cainikovs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 15:36:15

Jak już powiedzieli inni, ważne jest, aby być potocznym (dostosować style nazewnictwa i konwencje do bazy kodu, w której piszesz) i być spójnym.

Przez lata pracowałem nad dużą bazą kodu, która używa zarówno konwencji " this ->", jak i notacji podkreślenia postfix dla zmiennych członkowskich. Przez lata pracowałem również nad mniejszymi projektami, z których niektóre nie miały żadnej konwencji nazywania zmiennych członkowskich, a inne które miały różne konwencje nazewnictwa zmiennych członkowskich. Z tych mniejszych projektów konsekwentnie uważałem te, w których nie było żadnej konwencji, za najtrudniejsze do szybkiego i zrozumienia.

Jestem bardzo analna w kwestii nazewnictwa. Będę zadręczać się nad nazwą przypisaną klasie lub zmiennej do tego stopnia, że jeśli nie mogę wymyślić czegoś, co uważam za "dobre", zdecyduję się nazwać to czymś bezsensownym i podać komentarz opisujący to, co tak naprawdę jest. W ten sposób, przynajmniej nazwa oznacza dokładnie to, co zamierzam. nic więcej i nic mniej. I często, po użyciu go przez chwilę, odkrywam, jaka nazwa powinna być naprawdę i mogę wrócić i odpowiednio zmodyfikować lub refaktorować.

Ostatnia uwaga na temat IDE wykonującego pracę--to wszystko jest miłe i dobre, ale IDE często nie są dostępne w środowiskach, w których wykonuję najpilniejszą pracę. Czasami jedyną rzeczą dostępną w tym momencie jest Kopia "vi". Widziałem również wiele przypadków, w których uzupełnianie kodu IDE propagowało głupotę, taką jak nieprawidłowa pisownia w nazwach. Dlatego wolę nie polegać na oporze IDE.

 3
Author: Chris Cleeland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 16:08:20

Oryginalny pomysł na prefiksy w zmiennych składowych C++ polegał na przechowywaniu dodatkowych informacji o typach, o których kompilator nie wiedział. Na przykład, możesz mieć ciąg znaków o stałej długości, a inny, który jest zmienny i zakończony znakiem '\0'. Dla kompilatora oba są char *, ale jeśli spróbujesz kopiować z jednego do drugiego, wpadniesz w ogromne kłopoty. Więc, z czubka mojej głowy,

char *aszFred = "Hi I'm a null-terminated string";
char *arrWilma = {'O', 'o', 'p', 's'};

Gdzie" asz "oznacza, że zmienna jest" ASCII string (zero-zakończony) a " arr " oznacza, że ta zmienna jest tablicą znaków.

Wtedy dzieje się magia. Kompilator będzie całkowicie zadowolony z tego stwierdzenia:

strcpy(arrWilma, aszFred);

Ale Ty, jako człowiek, możesz spojrzeć na to i powiedzieć "Hej, te zmienne nie są tak naprawdę tego samego typu, nie mogę tego zrobić".

Niestety wiele miejsc używa standardów takich jak" m_ "dla zmiennych członkowskich," i "dla liczb całkowitych bez względu na sposób użycia," cp " dla wskaźników znakowych. Innymi słowy powielają to, co kompilator wie, i utrudniając jednocześnie odczyt kodu. Uważam, że ta szkodliwa praktyka powinna być zakazana przez ustawę i podlegać surowym karom.

Na koniec, są dwie kwestie, o których powinienem wspomnieć:

  • rozsądne użycie funkcji C++ pozwala kompilatorowi poznać informacje, które trzeba było zakodować w surowych zmiennych w stylu C. Możesz tworzyć klasy, które zezwalają tylko na prawidłowe operacje. Należy to zrobić tak bardzo, jak praktyczne.
  • jeśli Twoje bloki kodu są tak długie, że zapominasz, jaki typ jest zmienna przed jej użyciem, są one sposób zbyt długie. Nie używaj imion, Zmień organizację.
 3
Author: A. L. Flanagan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 16:40:32

Nasz projekt zawsze używał" its "jako prefiksu dla danych członkowskich i" the " jako prefiksu dla parametrów, bez prefiksu dla mieszkańców. Jest to trochę słodkie, ale zostało przyjęte przez wczesnych twórców naszego systemu, ponieważ widzieli go jako konwencję przez niektóre komercyjne biblioteki źródłowe, z których korzystaliśmy w tym czasie (albo XVT, albo RogueWave - może obie). Więc dostaniesz coś takiego:

void
MyClass::SetName(const RWCString &theName)
{
   itsName = theName;
}

Wielki powód, dla którego widzę przedrostki (i nie ma innych-nienawidzę Węgierskiej notacji) zapobiega to wpadaniu w kłopoty przez pisanie kodu, w którym myślisz, że odnosisz się do jednej zmiennej, ale tak naprawdę odnosisz się do innej zmiennej o tej samej nazwie zdefiniowanej w lokalnym zakresie. Pozwala to również uniknąć problemu wymyślania nazw zmiennych, które reprezentują tę samą koncepcję, ale z różnymi zakresami, jak w powyższym przykładzie. W takim przypadku musiałbyś wymyślić jakiś prefiks lub inną nazwę dla parametru "theName" - dlaczego nie zrobić spójnego zasada, która obowiązuje wszędzie.

Samo użycie tego - > nie jest wystarczająco dobre - nie jesteśmy tak zainteresowani zmniejszaniem wieloznaczności, jak zmniejszaniem błędów kodowania, a maskowanie nazw z lokalnie skalowanymi identyfikatorami może być uciążliwe. Niektóre Kompilatory mogą mieć możliwość zgłaszania ostrzeżeń w przypadkach, w których nazwa została zamaskowana w większym zakresie, ale ostrzeżenia te mogą stać się uciążliwe, jeśli pracujesz z dużym zestawem bibliotek stron trzecich, które wybrały nazwy dla nieużywane zmienne, które czasami zderzają się z twoimi własnymi.

Jeśli chodzi o its / the itself-szczerze mówiąc łatwiej jest pisać niż podkreślenia (jako typer dotykowy unikam podkreślenia, gdy tylko jest to możliwe - za bardzo rozciągam się od wierszy domowych), i uważam, że jest bardziej czytelny niż tajemniczy podkreślenie.

 3
Author: Steve Broberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 17:29:15

Używam go, ponieważ Intellisense VC++nie może powiedzieć, kiedy pokazać prywatnych użytkowników, gdy uzyskują dostęp poza klasą. Jedynym wskazaniem jest mały symbol "blokady" na ikonie pola na liście Intellisense. Po prostu ułatwia identyfikację prywatnych członków (pól). Również zwyczaj z C# szczerze mówiąc.

class Person {
   std::string m_Name;
public:
   std::string Name() { return m_Name; }
   void SetName(std::string name) { m_Name = name; }
};

int main() {
  Person *p = new Person();
  p->Name(); // valid
  p->m_Name; // invalid, compiler throws error. but intellisense doesn't know this..
  return 1;
}
 2
Author: Zack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 17:52:58

Myślę, że jeśli potrzebujesz prefiksów, aby odróżnić członków klasy od parametrów funkcji member i zmiennych lokalnych, albo funkcja jest zbyt duża, albo zmienne są źle nazwane. Jeśli nie mieści się na ekranie, dzięki czemu można łatwo zobaczyć, co jest czym, refactor.

Biorąc pod uwagę, że często są deklarowane daleko od miejsca, w którym są używane, uważam, że konwencje nazewnicze dla stałych globalnych (i zmiennych globalnych, chociaż IMO rzadko zdarza się ich używać) mają sens. Ale inaczej nie widzę potrzeby.

To powiedziawszy, kładłem podkreślenie na końcu wszystkich członków klasy prywatnej. Ponieważ wszystkie moje dane są prywatne, oznacza to, że Członkowie mają końcowe podkreślenie. Zwykle nie robię tego już w nowych bazach kodu, ale ponieważ jako programista pracujesz głównie ze starym kodem, wciąż robię to często. Nie jestem pewien, czy moja tolerancja na ten nawyk wynika z tego, że robiłem to zawsze i nadal robię to regularnie, czy naprawdę sprawia, że bardziej sensowne niż oznaczanie zmiennych członkowskich.

 2
Author: sbi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-06 14:32:40

W Pythonie wiodące podwójne podkreślniki są używane do emulowania prywatnych członków. Więcej szczegółów w Ta odpowiedź

 2
Author: Konstantin Tenzin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:56

Przydatne jest rozróżnianie zmiennych członkowskich od zmiennych lokalnych ze względu na zarządzanie pamięcią. Ogólnie rzecz biorąc, zmienne składowe przydzielane stercie powinny być niszczone w destruktorze, podczas gdy zmienne lokalne przydzielane stercie powinny być niszczone w tym zakresie. Zastosowanie konwencji nazewnictwa do zmiennych członkowskich ułatwia prawidłowe zarządzanie pamięcią.

 1
Author: frankster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 16:32:27

Kod Complete poleca m_varname dla zmiennych członkowskich.

Chociaż nigdy nie sądziłem, że notacja m_ jest przydatna, to przy budowaniu standardu podałbym wagę opinii McConnella.

 1
Author: Paul Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 18:04:48

Prawie nigdy nie używam przedrostków przed nazwami moich zmiennych. Jeśli używasz wystarczająco przyzwoitego IDE, powinieneś być w stanie łatwo refaktorować i znaleźć odniesienia. Używam bardzo jasnych nazw i nie boję się mieć długich nazw zmiennych. Z tą filozofią też nigdy nie miałem problemów.

Jedyny raz używam prefiksu w linii podpisu. Będę prefiks parametry do metody z _ więc mogę programować defensywnie wokół nich.

 1
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-04 21:13:49

Nigdy nie powinieneś potrzebować takiego prefiksu. Jeśli taki prefiks daje ci jakąkolwiek przewagę, Twój styl kodowania w ogóle wymaga naprawy, a to nie prefiks powstrzymuje twój kod od bycia jasnym. Typowe złe nazwy zmiennych to" inne "lub " 2". Nie naprawiasz tego, wymagając, aby była matką, naprawiasz to, nakłaniając dewelopera do zastanowienia się, co ta zmienna robi tam w kontekście tej funkcji. Może miał na myśli remoteSide, newValue, secondTestListener lub coś w ten zakres.

To skuteczny anachronizm, który wciąż jest propagowany zbyt daleko. Przestań prefiksować zmienne i nadaj im nazwy własne, których jasność odzwierciedla czas ich używania. Do 5 linii można nazwać go " i " bez nieporozumień; poza 50 liniami potrzebujesz dość długiej nazwy.

 1
Author: dascandy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-05 12:09:34

Lubię, aby nazwy zmiennych nadawały tylko znaczenie wartościom, które zawierają, i zostawiały sposób ich deklarowania/implementacji poza nazwą. Chcę wiedzieć, co oznacza wartość, kropka. Może zrobiłem więcej niż przeciętną ilość refaktoryzacji, ale uważam, że osadzanie tego, jak coś jest zaimplementowane w nazwie, sprawia, że refaktoryzacja jest bardziej żmudna niż musi być. Prefiksy wskazujące gdzie lub w jaki sposób deklarowane są elementy obiektu są specyficzne dla implementacji.

color = Red;

Przez większość czasu, ja nie obchodzi mnie, czy Red jest enum, strukturą, czy czymkolwiek innym, a jeśli funkcja jest tak duża, że nie pamiętam, czy kolor został zadeklarowany lokalnie, czy jest członkiem, prawdopodobnie nadszedł czas, aby podzielić funkcję na mniejsze jednostki logiczne.

Jeśli twoja złożoność cyklomatyczna jest tak wielka, że nie możesz śledzić tego, co dzieje się w kodzie bez wskazówek związanych z implementacją osadzonych w nazwach rzeczy, najprawdopodobniej musisz zmniejszyć złożoność swojej funkcji/metody.

Głównie, I używaj tylko "this" W konstruktorach i inicjalizatorach.

 1
Author: ChrisG65,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-25 19:16:48

Używam m_ dla zmiennych członkowskich tylko do korzystania z Intellisense i powiązanych funkcji IDE. Kiedy koduję implementację klasy, mogę wpisać m_ i zobaczyć combobox ze wszystkimi członkami M_ zgrupowanymi razem.

Ale mógłbym żyć bez m_ ' s bez problemu, oczywiście. To tylko mój styl pracy.

 0
Author: Hernán,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-30 03:39:00

Według JOINT STRIKE FIGHTER Air VEHICLE C++ CODING STANDARDS (grudzień 2005):

AV art. 67

Publiczne i chronione dane powinny być wykorzystywane tylko w struktury - Nie klasy. Uzasadnienie: klasa jest w stanie utrzymać swoje niezmienny poprzez kontrolowanie dostępu do swoich danych. Jednak klasa nie może kontroluj dostęp do swoich członków, jeśli ci członkowie nie są prywatni. Stąd wszystkie dane w klasie powinny być prywatne.

W ten sposób przedrostek "m" staje się bezużyteczny, ponieważ wszystkie dane powinny być szeregowy.

Ale dobrym nawykiem jest używanie przedrostka p przed wskaźnikiem, ponieważ jest to niebezpieczna zmienna.

 0
Author: Pierre-Louis Deschamps,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Wiele z tych konwencji pochodzi z czasów bez wyrafinowanych edytorów. Polecam użycie odpowiedniego IDE, które pozwala pokolorować każdy rodzaj zmiennej. Kolor jest o wiele łatwiejszy do zauważenia niż jakikolwiek prefiks.

Jeśli chcesz uzyskać więcej szczegółów na temat zmiennej, każde nowoczesne IDE powinno być w stanie pokazać ci ją, przesuwając nad nią karetkę lub kursor. A jeśli używasz zmiennej w niewłaściwy sposób (na przykład wskaźnik z . operator) i tak dostaniesz błąd.

 0
Author: Elias Mueller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-24 08:30:26