development

C ++ 클래스의 멤버 변수에 접두사를 사용하는 이유

big-blog 2020. 6. 22. 07:19
반응형

C ++ 클래스의 멤버 변수에 접두사를 사용하는 이유


많은 C ++ 코드는 멤버 변수를 표시하기 위해 구문 규칙을 사용합니다. 일반적인 예는 다음과 같습니다.

  • 공개 멤버의 m_ memberName (공개 멤버가 전혀 사용되지 않는 곳)
  • 개인 구성원 또는 모든 구성원의 _ memberName

다른 사람들 은 멤버 변수가 사용될 때마다 this-> 멤버를 사용하려고합니다 .

내 경험상 가장 큰 코드 기반은 이러한 규칙을 일관되게 적용하지 못합니다.

다른 언어에서는 이러한 규칙이 훨씬 덜 널리 퍼져 있습니다. Java 또는 C # 코드에서만 가끔 나타납니다. 루비 또는 파이썬 코드에서는 본 적이 없다고 생각합니다. 따라서 멤버 변수에 특별한 마크 업을 사용하지 않는 최신 언어가있는 경향이 있습니다.

이 컨벤션은 오늘날 C ++에서 여전히 유용합니까, 아니면 단지 비동기 일뿐입니다. 특히 라이브러리 전체에서 일관되지 않게 사용됩니다. 다른 언어는 멤버 접두어없이 할 수 있음을 보여주지 않았습니까?


밑줄을 사용할 때는주의해야합니다. 단어의 대문자 앞에있는 밑줄은 예약되어 있습니다. 예를 들면 다음과 같습니다.

_Foo

_엘

모든 예약어입니다

_foo

_엘

아닙니다. 소문자 앞에 선행 밑줄을 사용할 수없는 다른 상황이 있습니다. 필자의 경우 _L이 Visual C ++ 2005에 예약되어 있으며 충돌로 인해 예기치 않은 결과가 발생했습니다.

지역 변수를 표시하는 것이 얼마나 유용한 지 울타리에 있습니다.

다음은 예약 된 식별자에 대한 링크 입니다. C ++ 식별자에서 밑줄을 사용하는 규칙은 무엇입니까?


나는 모두 접두사 를 선호 합니다 .

나는 (시스템) 헝가리어 표기법이 접두사가 얻는 "나쁜 랩"의 대부분을 담당한다고 생각합니다.

이 표기법은 예를 들어 C ++ "lpsz"와 같이 강력하게 유형이 지정된 언어에서는 크게 의미가 없습니다. 다음과 같은 경우 문자열이 널 종료 문자열에 대한 긴 포인터임을 나타냅니다. char 배열과 "customerName"이 문자열이라는 것을 알기 란 쉽지 않습니다!

그러나 접두사를 사용하여 변수 사용법 을 지정합니다 (필수적으로 "Apps Hungarian", System Hungarian과의 불공평 한 관계로 인해 헝가리어라는 용어를 피하는 것을 선호하지만). 이것은 매우 편리한 시간 절약버그 감소 접근법.

나는 사용한다:

  • 회원의 경우 m
  • 상수 / 읽기 전용의 경우 c
  • 포인터의 경우 p (포인터의 포인터의 경우 pp)
  • 휘발성에 대한 v
  • 정적의 경우
  • 인덱스와 반복자의 경우
  • 이벤트의 경우 e

유형을 명확 하게하고 싶을 때는 표준 접미사 (예 : List, ComboBox 등)를 사용하십시오.

이를 통해 프로그래머 는 변수를 보거나 사용할 때마다 변수 사용법 을 알 수 있습니다. 아마도 가장 중요한 경우는 포인터에 대해 "p"입니다 (용법이 var.에서 var->로 변경되고 포인터 (Null, 포인터 산술 등)에 훨씬 더주의를 기울여야하기 때문에)이지만 다른 모든 것들은 매우 편리합니다.

예를 들어 단일 함수에서 동일한 변수 이름을 여러 방법으로 사용할 수 있습니다 (여기서는 C ++ 예제이지만 여러 언어에 동일하게 적용됨).

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

당신은 여기에서 볼 수 있습니다 :

  • 멤버와 매개 변수가 혼동되지 않습니다
  • 인덱스 / 반복자와 아이템이 혼동되지 않습니다
  • "count", "index"와 같은 일반적인 (모호한) 이름의 많은 함정을 피하는 명확하게 관련된 변수 (항목 목록, 포인터 및 색인) 세트를 사용하십시오.
  • 접두사는 "itemIndex"및 "itemPtr"과 같은 대안보다 타이핑을 줄이고 (짧고 자동 완성 기능을 더 잘 수행합니다)

"iName"이터레이터의 또 다른 장점은 잘못된 인덱스로 배열을 인덱싱하지 않는다는 것입니다. 다른 루프 내에서 루프를 복사하면 루프 인덱스 변수 중 하나를 리팩터링 할 필요가 없습니다.

이 비현실적으로 간단한 예를 비교해보십시오.

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

(읽기 어렵고 종종 "j"가 사용 된 곳에서 "i"를 사용하게 됨)

와:

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

(이것은 훨씬 더 읽기 쉽고 인덱싱에 대한 모든 혼란을 제거합니다. 최신 IDE에서 자동 완성 기능을 사용하면 빠르고 쉽게 입력 할 수 있습니다)

다음 이점은 코드 스 니펫 이 컨텍스트 를 이해할 필요가 없다는 것입니다. 두 줄의 코드를 전자 메일이나 문서에 복사 할 수 있으며 해당 스 니펫을 읽는 사람은 모든 멤버, 상수, 포인터, 색인 등의 차이점을 알 수 있습니다. "아 추가 할 필요가 없습니다. 'data'는 포인터에 대한 포인터 '입니다. 왜냐하면'ppData '입니다.

같은 이유로, 나는 그것을 이해하기 위해 코드 라인에서 눈을 움직일 필요가 없습니다. 'data'가 로컬, 매개 변수, 멤버 또는 상수인지 확인하기 위해 코드를 검색 할 필요가 없습니다. 마우스로 손을 움직일 필요가 없으므로 '데이터'위에 포인터를 놓고 툴팁 (때로는 나타나지 않는)이 나타날 때까지 기다릴 수 있습니다. 따라서 프로그래머는 검색 및 검색 또는 대기 시간을 낭비하지 않기 때문에 코드를 훨씬 빠르게 읽고 이해할 수 있습니다 .

(물건을 찾기 위해 위아래로 검색하는 데 시간을 낭비하지 않는다고 생각되면 1 년 전에 작성했지만 이후에 보지 않은 코드를 찾으십시오. 파일을 열고 읽지 않고 반쯤 줄어 듭니다. 방법보기 무언가가 멤버, 매개 변수 또는 로컬인지 알기 전에이 시점부터 읽을 수 있습니다. 이제 임의의 다른 위치로 이동하십시오. 또는 함수 호출 방법을 이해하려고 시도)

'm'접두어는 또한 (IMHO) 추악하고 말끔한 "this->"표기법과 그것이 보장하지 않는 불일치를 피합니다 (주의해서도 'this-> data'와 동일한 클래스의 '데이터'는 이름의 일관된 철자를 강제하지 않습니다.

'이'표기법은 모호성 을 해결하기위한 것입니다.하지만 왜 모호 할 수있는 코드를 의도적으로 작성하는 사람이 있습니까? 모호성 조만간 버그로 이어질 입니다. 그리고 일부 언어에서는 'this'를 정적 멤버에 사용할 수 없으므로 코딩 스타일에 '특별한 경우'를 도입해야합니다. 나는 명시적이고 모호하지 않으며 일관된 모든 곳에 적용되는 하나의 간단한 코딩 규칙을 선호합니다.

마지막 주요 이점은 Intellisense 및 자동 완성 기능입니다. Windows Form에서 Intellisense를 사용하여 이벤트를 찾으십시오. 이벤트를 찾기 위해 호출 할 필요가없는 수백 가지의 신비한 기본 클래스 메소드를 스크롤해야합니다. 그러나 모든 이벤트에 "e"접두사가 있으면 "e"아래의 그룹에 자동으로 나열됩니다. 따라서 접두사는 지능 목록에서 멤버, const, 이벤트 등을 그룹화하여 원하는 이름을 훨씬 빠르고 쉽게 찾을 수 있도록합니다. (보통, 메소드에는 범위 내에서 액세스 할 수있는 약 20-50 개의 값 (로컬, 매개 변수, 멤버, const, 이벤트)이있을 수 있지만 접 두부를 입력 한 후 (지금 색인을 사용하고 싶습니다.) 'i. .. '), 2-5 개의 자동 완성 옵션 만 제공됩니다.

나는 게으른 프로그래머이고 위의 규칙은 많은 작업을 절약합니다. 모든 변수를 어떻게 사용해야하는지 알고 있기 때문에 더 빨리 코딩 할 수 있고 실수도 훨씬 줄어 듭니다.


반대론

그렇다면 단점은 무엇입니까? 접두사에 대한 일반적인 인수는 다음과 같습니다.

  • "접두사 계획은 / 악 나쁜" . 나는 "m_lpsz"와 그 ilk가 제대로 생각되지 않고 완전히 쓸모 없다는 것에 동의합니다. 그렇기 때문에 상황에 맞지 않는 것을 복사하는 대신 요구 사항을 지원하도록 잘 설계된 표기법을 사용하는 것이 좋습니다. (작업에 맞는 도구를 사용하십시오).

  • "사용 방법을 변경하면 이름을 바꿔야합니다 . " 물론 리팩토링이 중요한 이유이며 IDE에이 작업을 빠르고 쉽게 수행 할 수있는 리팩토링 도구가있는 이유가 여기에 있습니다. 접두사가 없어도 변수 사용법을 변경하면 이름 이 변경 되어야 합니다.

  • "접두사는 저를 혼동합니다" . 사용 방법을 익힐 때까지 모든 도구와 마찬가지로 당신의 두뇌가 네이밍 패턴에 익숙해지면, 정보를 자동으로 걸러 내고 접두사가 더 이상 존재하지 않을 것입니다. 그러나 실제로 "유창한"상태가되기 전에 1-2 주 동안 이와 같은 체계를 사용해야합니다. 그리고 많은 사람들이 오래된 코드를보고 좋은 접두사 체계 없이 어떻게 관리했는지 궁금해하기 시작합니다 .

  • "이 작업을 수행하는 코드 만 살펴볼 수 있습니다 . " 예, 그러나 코드의 다른 곳을 보거나 이미 눈에 초점을 맞춘 지점에 대한 답변이 올 바르면 모든 세부 사항을 기억하는 데 시간을 낭비하지 않아도됩니다.

  • (일부) 해당 정보는 툴팁이 내 변수에 나타날 때까지 기다리면 찾을 수 있습니다 . 예. 지원되는 경우 일부 접두사 유형의 경우 코드가 깔끔하게 컴파일 될 때 대기 후 설명을 읽고 접두사가 즉시 전달한 정보를 찾을 수 있습니다. 접두사가 더 간단하고 안정적이며 효율적인 방법이라고 생각합니다.

  • "더 많은 타이핑입니다" . 정말? 하나의 전체 문자 더? 또는 IDE 자동 완성 도구를 사용하면 각 접두사 문자가 검색 공간을 크게 좁히기 때문에 입력이 줄어드는 경우가 많습니다. "e"를 누르면 수업의 세 가지 이벤트가 지능적으로 나타납니다. "c"를 누르면 5 개의 상수가 나열됩니다.

  • " this->대신에 사용할 수 있습니다 m" . 그래, 할 수있어 그러나 그것은 훨씬 더 추악하고 더 자세한 접두사입니다! 컴파일러에게는 선택 사항 이므로 사용법이 일관되지 않기 때문에 (특히 팀에서) 훨씬 큰 위험을 감수 합니다. m반면에 간단하고 명확하며 명시 적이며 선택 사항이 아니므로 실수로 사용하는 것이 훨씬 어렵습니다.


나는 일반적으로 멤버 변수에 접두사를 사용하지 않습니다.

m"C ++에는 이미 회원 액세스를위한 표준 접두사가 있습니다."라고 지적 할 때까지 접두사 를 사용했습니다 this->.

이것이 제가 지금 사용하는 것입니다. 즉, 모호성이 있는 경우 this->접두사를 추가 하지만 일반적으로 모호성이 없으며 변수 이름을 직접 참조 할 수 있습니다.

나에게, 그것은 두 세계의 최고입니다. 필요할 때 사용할 수있는 접두사가 있으며 가능할 때마다 그대로 둘 수 있습니다.

물론 이것에 대한 명백한 반대는 "그렇다. 그러나 변수가 클래스 멤버인지 아닌지를 한눈에 볼 수는 없다".

내가 "그렇게 무엇을 말해야합니까? 만약 당신이 그것을 알아야 할 필요가 있다면, 당신의 클래스는 아마도 너무 많은 상태를 가질 것입니다.

실제로, 나는 이것이 매우 잘 작동한다는 것을 알았습니다. 추가 보너스로 이름을 바꾸지 않고도 로컬 변수를 클래스 멤버 (또는 다른 방법)로 쉽게 승격시킬 수 있습니다.

그리고 무엇보다도 일관성이 있습니다! 일관성을 유지하기 위해 특별한 조치를 취하거나 규칙을 기억할 필요가 없습니다.


그건 그렇고, 반원에게 밑줄을 사용 해서는 안됩니다 . 구현에 의해 예약 된 이름에 불편하게 접근 할 수 있습니다.

표준은 이중 밑줄 또는 밑줄로 시작하고 뒤에 대문자로 된 모든 이름을 예약합니다. 또한 글로벌 네임 스페이스에서 단일 밑줄 시작하는 모든 이름을 예약합니다 .

따라서 밑줄과 소문자가 뒤 따르는 클래스 멤버는 합법적이지만 조만간 대문자로 시작하는 식별자와 동일하게하거나 위의 규칙 중 하나를 위반하게됩니다.

따라서 밑줄을 피하는 것이 더 쉽습니다. 변수 이름으로 범위를 인코딩하려면 접두사 밑줄을 사용 m_하거나 m접두사를 사용하십시오 .


다음과 같이 접미사 밑줄을 선호합니다.

class Foo
{
   private:
      int bar_;

   public:
      int bar() { return bar_; }
};

최근 접두사가없는 대신 m_ 접두사를 선호하는 경향이 있었기 때문에 그 이유는 멤버 변수를 플래그 지정하는 것이 중요하지 않지만 모호성을 피하기 위해 다음과 같은 코드가 있다고합니다.

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

원인은 효과가 없으며 하나만 foo허용됩니다. 옵션은 다음과 같습니다.

  • this->foo = foo;

    매개 변수 섀도 잉을 유발하므로 더 이상 g++ -Wshadow경고 를 사용할 수 없으며 더 이상 입력하지 않아도 m_됩니다. 또한 a int foo;와 a 가있을 때 변수와 함수 사이의 이름 충돌이 계속 발생 합니다 int foo();.

  • foo = foo_; 또는 foo = arg_foo;

    잠시 동안 그것을 사용했지만 인수 목록을 추악하게 만들었습니다. 문서는 구현에서 이름 모호성을 다루지 않아야합니다. 변수와 함수 사이의 이름 충돌도 여기에 존재합니다.

  • m_foo = foo;

    API 설명서는 깨끗하게 유지되므로 멤버 함수와 변수 사이에 모호함이 없으며 입력하기가 더 짧습니다 this->. 단점은 POD 구조를 추악하게 만든다는 것입니다. 그러나 POD 구조는 애매 모호성으로 인해 어려움을 겪지 않기 때문에 POD 구조와 함께 사용할 필요가 없습니다. 고유 한 접두사를 사용하면 검색 및 교체 작업이 더 쉬워집니다.

  • foo_ = foo;

    m_적용 의 장점의 대부분은 미학적 이유로 거부하지만, 밑줄 또는 선행 밑줄은 변수를 불완전하고 불균형하게 만듭니다. m_더 좋아 보인다. 전역 및 정적에 m_사용할 수 있으므로 사용 이 더 확장 가능 합니다.g_s_

추신 : m_파이썬이나 루비에서 보이지 않는 이유 는 두 언어가 모두 자신의 접두사를 적용하고, 루비는 @멤버 변수에 사용하고 파이썬에는이 필요하기 때문 self.입니다.


나는 그것이 얼마나 널리 퍼져 있는지 말할 수는 없지만 개인적으로 말하면 항상 멤버 변수 앞에 항상 'm'을 붙였습니다. 예 :

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

그것은 내가 사용하는 접두사의 유일한 형태입니다 (나는 매우 헝가리어 표기법입니다). 따로, 나는 일반적으로 이름 (또는 그 문제에 대한 다른 곳)에서 밑줄 사용을 비난하지만 전 처리기 매크로 이름은 일반적으로 모두 대문자이므로 예외를 만듭니다.


멤버 함수를 통해 읽을 때 각 변수를 "소유"하는 사람을 아는 것은 변수의 의미를 이해하는 데 절대적으로 필요합니다. 이 같은 기능에서 :

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

사과와 바나나가 어디에서 나오는지 알기 쉽지만 포도, 멜론, 스퍼 드는 어떻습니까? 전역 네임 스페이스를 살펴 봐야합니까? 수업 선언에서? 변수가이 객체의 멤버입니까 아니면이 객체 클래스의 멤버입니까? 이러한 질문에 대한 답을 모르면 코드를 이해할 수 없습니다. 그리고 더 긴 기능에서 사과와 바나나와 같은 지역 변수 선언도 셔플에서 사라질 수 있습니다.

전역 변수, 멤버 변수 및 정적 멤버 변수 (각각 g_, m_ 및 s_)에 대해 일관된 레이블을 추가하면 상황이 즉시 명확 해집니다.

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

처음에는 익숙해 져야 할 수도 있습니다.하지만 프로그래밍에서 그렇지 않은 것은 무엇입니까? {와}조차 당신에게 이상하게 보였던 하루가있었습니다. 그리고 일단 익숙해지면 코드를 훨씬 빨리 이해하는 데 도움이됩니다.

(m_ 대신 "this->"를 사용하는 것은 의미가 있지만 훨씬 더 오래 걸리고 시각적으로 파괴적입니다. 멤버 변수의 모든 용도를 표시하는 좋은 대안으로 생각하지는 않습니다.)

위의 인수에 대한 가능한 반대는 인수를 유형으로 확장하는 것입니다. 변수의 유형을 아는 것이 변수의 의미를 이해하는 데 절대적으로 필요하다는 것도 사실 일 수 있습니다. 그렇다면 유형을 식별하는 각 변수 이름에 접두사를 추가하지 않겠습니까? 이 논리를 사용하면 헝가리 표기법으로 끝납니다. 그러나 많은 사람들이 헝가리어 표기법을 힘들고 추악하고 도움이되지 않는다고 생각합니다.

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

헝가리어 않습니다코드에 대해 새로운 것을 알려주세요. 이제 Foo :: bar () 함수에 여러 암시 적 캐스트가 있음을 이해합니다. 코드의 문제점은 이제 헝가리어 접두사가 추가 한 정보의 가치가 시각적 비용에 비해 작다는 것입니다. C ++ 유형 시스템에는 유형이 함께 작동하거나 컴파일러 경고 또는 오류를 발생시키는 데 도움이되는 많은 기능이 포함되어 있습니다. 컴파일러는 타입을 다루는 데 도움을줍니다. 표기 할 필요는 없습니다. Foo :: bar ()의 변수가 숫자 일 수 있다는 것을 쉽게 추론 할 수 있습니다. 이것이 우리가 아는 한, 함수에 대한 일반적인 이해를 얻는 데 충분합니다. 따라서 각 변수의 정확한 유형을 아는 값은 상대적으로 낮습니다. 그러나 "s_dSpuds"(또는 "dSpuds")와 같은 변수의 추악함은 훌륭합니다. 그래서,


멤버 접두사의 주된 이유는 멤버 함수 로컬과 이름이 같은 멤버 변수를 구별하기위한 것입니다. 이것은 물건의 이름으로 게터를 사용할 때 유용합니다.

치다:

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

이 경우 멤버 변수를 full_name (으)로 호출 할 수 없습니다. 멤버 함수의 이름을 get_full_name ()으로 바꾸거나 멤버 변수를 어떻게 든 장식해야합니다.


한 구문이 다른 구문보다 실제 가치가 있다고 생각하지 않습니다. 언급했듯이 소스 파일 전체에서 균일 성이 떨어집니다.

내가 그런 규칙을 흥미롭게 생각하는 유일한 점은, 같은 이름의 두 가지가 필요할 때입니다.

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

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

I use it to differentiate the two. Also when I wrap calls, like from windows Dll, RecvPacket(...) from the Dll might be wrapped in RecvPacket(...) in my code. In these particular occasions using a prefix like "_" might make the two look alike, easy to identify which is which, but different for the compiler


Some responses focus on refactoring, rather than naming conventions, as the way to improve readability. I don't feel that one can replace the other.

I've known programmers who are uncomfortable with using local declarations; they prefer to place all the declarations at the top of a block (as in C), so they know where to find them. I've found that, where scoping allows for it, declaring variables where they're first used decreases the time that I spend glancing backwards to find the declarations. (This is true for me even for small functions.) That makes it easier for me to understand the code I'm looking at.

I hope it's clear enough how this relates to member naming conventions: When members are uniformly prefixed, I never have to look back at all; I know the declaration won't even be found in the source file.

나는 이러한 스타일을 선호하기 시작하지 않았다고 확신합니다. 그러나 시간이 지남에 따라 일관되게 사용되는 환경에서 일하면서 나는 그것들을 활용하기 위해 내 생각을 최적화했습니다. 나는 현재 그들에게 불편 함을 느끼는 많은 사람들이 일관된 사용법으로 그들을 선호하게 될 가능성이 있다고 생각합니다.


그 협약은 바로 그 것입니다. 대부분의 상점은 코드 규칙을 사용하여 코드를 쉽게 읽을 수 있으므로 누구나 쉽게 코드를보고 공개 및 개인 구성원과 같은 항목을 빠르게 해독 할 수 있습니다.


다른 사람들은 멤버 변수가 사용될 때마다 this-> member를 사용하려고합니다.

일반적으로 접두사가 없기 때문입니다 . 컴파일러는 문제의 변수를 해결하기 위해 충분한 정보가 필요합니다. 접두사로 인해 고유 한 이름이거나 this키워드 를 통해 가능합니다 .

So, yes, I think prefixes are still useful. I, for one, would prefer to type '_' to access a member rather than 'this->'.


Other languages will use coding conventions, they just tend to be different. C# for example has probably two different styles that people tend to use, either one of the C++ methods (_variable, mVariable or other prefix such as Hungarian notation), or what I refer to as the StyleCop method.

private int privateMember;
public int PublicMember;

public int Function(int parameter)
{
  // StyleCop enforces using this. for class members.
  this.privateMember = parameter;
}

In the end, it becomes what people know, and what looks best. I personally think code is more readable without Hungarian notation, but it can become easier to find a variable with intellisense for example if the Hungarian notation is attached.

In my example above, you don't need an m prefix for member variables because prefixing your usage with this. indicates the same thing in a compiler-enforced method.

This doesn't necessarily mean the other methods are bad, people stick to what works.


When you have a big method or code blocks, it's convenient to know immediately if you use a local variable or a member. it's to avoid errors and for better clearness !


IMO, this is personal. I'm not putting any prefixes at all. Anyway, if code is meaned to be public, I think it should better has some prefixes, so it can be more readable.

Often large companies are using it's own so called 'developer rules'.
Btw, the funniest yet smartest i saw was DRY KISS (Dont Repeat Yourself. Keep It Simple, Stupid). :-)


As others have already said, the importance is to be colloquial (adapt naming styles and conventions to the code base in which you're writing) and to be consistent.

For years I have worked on a large code base that uses both the "this->" convention as well as using a postfix underscore notation for member variables. Throughout the years I've also worked on smaller projects, some of which did not have any sort of convention for naming member variables, and other which had differing conventions for naming member variables. Of those smaller projects, I've consistently found those which lacked any convention to be the most difficult to jump into quickly and understand.

I'm very anal-retentive about naming. I will agonize over the name to be ascribed to a class or variable to the point that, if I cannot come up with something that I feel is "good", I will choose to name it something nonsensical and provide a comment describing what it really is. That way, at least the name means exactly what I intend it to mean--nothing more and nothing less. And often, after using it for a little while, I discover what the name should really be and can go back and modify or refactor appropriately.

One last point on the topic of an IDE doing the work--that's all nice and good, but IDEs are often not available in environments where I have perform the most urgent work. Sometimes the only thing available at that point is a copy of 'vi'. Also, I've seen many cases where IDE code completion has propagated stupidity such as incorrect spelling in names. Thus, I prefer to not have to rely on an IDE crutch.


The original idea for prefixes on C++ member variables was to store additional type information that the compiler didn't know about. So for example, you could have a string that's a fixed length of chars, and another that's variable and terminated by a '\0'. To the compiler they're both char *, but if you try to copy from one to the other you get in huge trouble. So, off the top of my head,

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

where "asz" means this variable is "ascii string (zero-terminated) and "arr" means this variable is a character array.

Then the magic happens. The compiler will be perfectly happy with this statement:

strcpy(arrWilma, aszFred);

But you, as a human, can look at it and say "hey, those variables aren't really the same type, I can't do that".

Unfortunately a lot places use standards such as "m_" for member variables, "i" for integers no matter how used, "cp" for char pointers. In other words they're duplicating what the compiler knows, and making the code hard to read at the same time. I believe this pernicious practice should be outlawed by statute and subject to harsh penalties.

Finally, there's two points I should mention:

  • Judicious use of C++ features allows the compiler to know the information you had to encode in raw C-style variables. You can make classes that will only allow valid operations. This should be done as much as practical.
  • If your code blocks are so long that you forget what type a variable is before you use it, they are way too long. Don't use names, re-organize.

Our project has always used "its" as a prefix for member data, and "the" as a prefix for parameters, with no prefix for locals. It's a little cutesy, but it was adopted by the early developers of our system because they saw it used as a convention by some commercial source libraries we were using at the time (either XVT or RogueWave - maybe both). So you'd get something like this:

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

The big reason I see for scoping prefixes (and no others - I hate Hungarian notation) is that it prevents you from getting into trouble by writing code where you think you're referring to one variable, but you're really referring to another variable with the same name defined in the local scope. It also avoids the problem of coming up with a variable names to represent that same concept, but with different scopes, like the example above. In that case, you would have to come up with some prefix or different name for the parameter "theName" anyway - why not make a consistent rule that applies everywhere.

Just using this-> isn't really good enough - we're not as interested in reducing ambiguity as we are in reducing coding errors, and masking names with locally scoped identifiers can be a pain. Granted, some compilers may have the option to raise warnings for cases where you've masked the name in a larger scope, but those warnings may become a nuisance if you're working with a large set of third party libraries that happen to have chosen names for unused variables that occasionally collide with your own.

As for the its/the itself - I honestly find it easier to type than underscores (as a touch typist, I avoid underscores whenever possible - too much stretching off the home rows), and I find it more readable than a mysterious underscore.


I use it because VC++'s Intellisense can't tell when to show private members when accessing out of the class. The only indication is a little "lock" symbol on the field icon in the Intellisense list. It just makes it easier to identify private members(fields) easier. Also a habit from C# to be honest.

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

I think that, if you need prefixes to distinguish class members from member function parameters and local variables, either the function is too big or the variables are badly named. If it doesn't fit on the screen so you can easily see what is what, refactor.

Given that they often are declared far from where they are used, I find that naming conventions for global constants (and global variables, although IMO there's rarely ever a need to use those) make sense. But otherwise, I don't see much need.

That said, I used to put an underscore at the end of all private class members. Since all my data is private, this implies members have a trailing underscore. I usually don't do this anymore in new code bases, but since, as a programmer, you mostly work with old code, I still do this a lot. I'm not sure whether my tolerance for this habit comes from the fact that I used to do this always and am still doing it regularly or whether it really makes more sense than the marking of member variables.


In python leading double underscores are used to emulate private members. For more details see this answer


It is useful to differentiate between member variables and local variables due to memory management. Broadly speaking, heap-allocated member variables should be destroyed in the destructor, while heap-allocated local variables should be destroyed within that scope. Applying a naming convention to member variables facilitates correct memory management.


Code Complete recommends m_varname for member variables.

While I've never thought the m_ notation useful, I would give McConnell's opinion weight in building a standard.


I almost never use prefixes in front of my variable names. If you're using a decent enough IDE you should be able to refactor and find references easily. I use very clear names and am not afraid of having long variable names. I've never had trouble with scope either with this philosophy.

The only time I use a prefix would be on the signature line. I'll prefix parameters to a method with _ so I can program defensively around them.


You should never need such a prefix. If such a prefix offers you any advantage, your coding style in general needs fixing, and it's not the prefix that's keeping your code from being clear. Typical bad variable names include "other" or "2". You do not fix that with requiring it to be mOther, you fix it by getting the developer to think about what that variable is doing there in the context of that function. Perhaps he meant remoteSide, or newValue, or secondTestListener or something in that scope.

It's an effective anachronism that's still propagated too far. Stop prefixing your variables and give them proper names whose clarity reflects how long they're used. Up to 5 lines you could call it "i" without confusion; beyond 50 lines you need a pretty long name.


I like variable names to give only a meaning to the values they contain, and leave how they are declared/implemented out of the name. I want to know what the value means, period. Maybe I've done more than an average amount of refactoring, but I find that embedding how something is implemented in the name makes refactoring more tedious than it needs to be. Prefixes indicating where or how object members are declared are implementation specific.

color = Red;

Most of the time, I don't care if Red is an enum, a struct, or whatever, and if the function is so large that I can't remember if color was declared locally or is a member, it's probably time to break the function into smaller logical units.

If your cyclomatic complexity is so great that you can't keep track of what is going on in the code without implementation-specific clues embedded in the names of things, most likely you need to reduce the complexity of your function/method.

Mostly, I only use 'this' in constructors and initializers.


I use m_ for member variables just to take advantage of Intellisense and related IDE-functionality. When I'm coding the implementation of a class I can type m_ and see the combobox with all m_ members grouped together.

But I could live without m_ 's without problem, of course. It's just my style of work.


According to JOINT STRIKE FIGHTER AIR VEHICLE C++ CODING STANDARDS (december 2005):

AV Rule 67

Public and protected data should only be used in structs—not classes. Rationale: A class is able to maintain its invariant by controlling access to its data. However, a class cannot control access to its members if those members non-private. Hence all data in a class should be private.

Thus, the "m" prefix becomes unuseful as all data should be private.

But it is a good habit to use the p prefix before a pointer as it is a dangerous variable.


Many of those conventions are from a time without sophisticated editors. I would recommend using a proper IDE that allows you to color every kind of variable. Color is by far easier to spot than any prefix.

If you need to get even more detail on a variable any modern IDE should be able to show it to you by moving the caret or cursor over it. And if you use a variable in a wrong way (for instance a pointer with the . operator) you will get an error, anyway.

참고URL : https://stackoverflow.com/questions/1228161/why-use-prefixes-on-member-variables-in-c-classes

반응형