web-dev-qa-db-ja.com

C ++クラスのメンバー変数にプレフィックスを使用する理由

多くのC++コードは、メンバー変数をマークアップするために構文規則を使用しています。一般的な例は次のとおりです。

  • m _memberNameパブリックメンバーの場合(パブリックメンバーが使用される場合)
  • _memberNameプライベートメンバーまたはすべてのメンバー

他の人は、メンバー変数が使用されるたびにthis-> memberの使用を強制しようとします。

私の経験では、大規模なコードベースのほとんどは、このようなルールを一貫して適用できません。

他の言語では、これらの規則はあまり普及していません。 JavaまたはC#コードでまれにしか見られません。 RubyまたはPythonコードで見たことがないと思います。したがって、より現代的な言語では、メンバー変数に特別なマークアップを使用しない傾向があります。

この規則は今日でもC++で有用ですか、それとも単なる時代錯誤ですか。特に、ライブラリ全体で一貫性がないために使用されるためです。他の言語は、メンバープレフィックスなしで実行できることを示していませんか?

137
VoidPointer

先頭のアンダースコアの使用には注意する必要があります。 Wordの大文字の前にある下線は予約されています。例えば:

_Foo

_L

すべて予約語です

_foo

_l

ありません。小文字の前に先行するアンダースコアが許可されない他の状況があります。私の特定のケースでは、_LがVisual C++ 2005によって予約されており、クラッシュにより予期しない結果が生じることがわかりました。

私は、ローカル変数をマークアップすることがどれほど有用かについてフェンスにいます。

以下に、どの識別子が予約されているかについてのリンクを示します。 C++識別子でアンダースコアを使用する場合の規則は何ですか?

44
Juan

prefixes done wellを支持しています。

(システム)ハンガリー語の表記法は、接頭辞が取得する「悪いラップ」のほとんどの原因であると思います。

この表記は、強く型付けされた言語ではほとんど意味がありません。 C++「lpsz」では、文字列がnulで終了する文字列への長いポインタであることがわかります。セグメント化されたアーキテクチャが古代史である場合、C++文字列はnulで終了するchar配列への一般的なポインタであり、実際にはそれほど難しくありません「customerName」が文字列であることを知るために!

ただし、変数のusageを指定するためにプレフィックスを使用します(本質的に「Apps Hungarian」。ただし、ハンガリー語という用語はSystem Hungarianとの悪い不公平な関係)、これは非常に便利なtimesavingおよびbug-reducingのアプローチです。

私が使う:

  • メンバーの場合はm
  • 定数/読み取り専用のc
  • ポインターのp(およびポインターへのポインターのpp)
  • v揮発性の
  • 静的な場合
  • インデックスとイテレータのi
  • イベントの場合はe

typeを明確にする場合は、標準のサフィックス(List、ComboBoxなど)を使用します。

これにより、プログラマは変数を(使用するたびに)変数のusageに気付きます。おそらく最も重要なケースはポインターの「p」です(使用法がvar。からvar->に変更されており、ポインター(NULL、ポインター演算など)にはさらに注意する必要があるため)が、他のすべては非常に便利です。

たとえば、1つの関数で複数の方法で同じ変数名を使用できます(ここでは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」イテレータのもう1つの優れた点は、間違ったインデックスで配列のインデックスを作成することはなく、ループを別のループ内にコピーする場合、ループインデックス変数の1つをリファクタリングする必要がないことです。

この非現実的に単純な例を比較してください。

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のオートコンプリートでは、これもすばやく簡単に入力できます)

次の利点は、コードスニペットを理解するためにコンテキストを必要としないことです。 2行のコードを電子メールまたはドキュメントにコピーできます。そのスニペットを読むと、すべてのメンバー、定数、ポインター、インデックスなどの違いを知ることができます。「ああ、追加する必要はありません。 「data」は「ppData」と呼ばれるため、「ポインターへのポインター」です。

同じ理由で、コード行を理解するために目を離す​​必要はありません。 「データ」がローカル、パラメーター、メンバー、または定数であるかどうかを見つけるためにコードを検索する必要はありません。マウスに手を動かす必要はないので、ポインタを「データ」の上に置いて、ツールチップ(ときどき表示されない)がポップアップするのを待つことができます。そのため、プログラマーは、検索(上下)や待機に時間を無駄にしないため、コードを大幅に速く読んで理解できます。

(上下に検索して時間を無駄にすると思わない場合は、1年前に書いたのでまだ見ていないコードを見つけてください。ファイルを開いて飛び回ってください読み進めずに途中まで読みます。メンバー、パラメーター、ローカルのいずれであるかわからなくなる前に、このポイントからどれだけ読み込めるかを確認します。今度は別のランダムな場所にジャンプします。他の人のコードをシングルステップ実行するとき、または他の人の関数を呼び出す方法を理解しようとするとき)

また、「m」プレフィックスは、(IMHO)wordくて冗長な「this->」表記、およびそれが保証する矛盾を回避します(注意を払っても、通常は「this-> data」と名前の一貫したスペルを強制するものは何もないため、同じクラスの「データ」)。

'this'表記はambiguityを解決することを目的としています-しかし、なぜだれかがあいまいなコードを意図的に書くのでしょうか?あいまいさwillは、遅かれ早かれバグにつながります。また、一部の言語では「this」を静的メンバーに使用できないため、コーディングスタイルに「特殊なケース」を導入する必要があります。私はどこにでも適用できる単一のシンプルなコーディングルールを持つことを好みます-明示的、明確、一貫性があります。

最後の主な利点は、IntelliSenseと自動補完です。 WindowsフォームでIntellisenseを使用してイベントを見つけてみてください。イベントを見つけるために呼び出す必要のない、数百の不可解な基本クラスメソッドをスクロールする必要があります。ただし、すべてのイベントに「e」プレフィックスが付いている場合、それらは自動的に「e」の下のグループにリストされます。したがって、プレフィックスは、インテリセンスリスト内のメンバー、定数、イベントなどをグループ化するために機能し、必要な名前をより迅速かつ簡単に見つけることができます。 (通常、メソッドにはスコープ内でアクセス可能な20〜50の値(ローカル、パラメーター、メンバー、定数、イベント)があります。ただし、プレフィックスを入力した後(今はインデックスを使用したいので、「i」と入力します。 .. ')、2〜5個のオートコンプリートオプションのみが表示されます。プレフィックスと意味のある名前に「余分なタイピング」属性があると、検索スペースが大幅に減少し、開発速度が大幅に向上します)

私は怠け者のプログラマーであり、上記の規則により多くの作業を節約できます。すべての変数をどのように使用するかを知っているので、コーディングを高速化でき、ミスをはるかに少なくできます。


引数に対する

それで、短所は何ですか?プレフィックスに対する一般的な引数は次のとおりです。

  • 「プレフィックススキームは悪/悪」。 「m_lpsz」とその同類はあまり考えられておらず、まったく役に立たないことに同意します。だからこそ、あなたの状況にふさわしくないものをコピーするのではなく、あなたの要件をサポートするように設計された適切に設計された表記法を使用することをお勧めします。 (ジョブに適切なツールを使用します)。

  • "何かの使用法を変更した場合、名前を変更する必要があります"。はい、もちろんそうです。それがリファクタリングのすべてであり、IDEにこの作業を迅速かつ無痛で行うためのリファクタリングツールがある理由です。接頭辞がなくても、変数の使用法を変更すると、ほぼ確実にその名前oughtを変更することになります。

  • 「接頭辞は私を混乱させる」。あなたがそれを使用する方法を学ぶまで、すべてのツールと同様に。脳が命名パターンに慣れると、脳は自動的に情報を除外し、接頭辞がもうあることを気にしなくなります。しかし、実際に「流fluent」になる前に、このようなスキームを1、2週間しっかりと使用する必要があります。そして、それは多くの人々が古いコードを見て、どのように優れたプレフィックススキームを(without)管理したのか疑問に思うときです。

  • 「コードを見て、これを解決することができます」。はい。ただし、コードの別の場所を調べたり、既に焦点が合っている場所で答えが正しい場合は、コードの細部を覚えておく必要はありません。

  • (一部)その情報は、変数にツールチップがポップアップするのを待つだけで見つけることができます。はい。サポートされている場合、一部の種類のプレフィックスについては、コードが正常にコンパイルされると、待機後に説明を読み、プレフィックスが即座に伝えた情報を見つけることができます。プレフィックスは、よりシンプルで信頼性が高く、効率的なアプローチであると感じています。

  • 「もっとタイピングします」。本当に?キャラクター全体がもう1つ?それとも-IDE自動補完ツールを使用すると、各プレフィックス文字が検索スペースを大幅に狭めるため、入力を減らすことがよくあります。 「e」を押すと、クラスの3つのイベントがインテリセンスでポップアップします。 「c」を押すと、5つの定数がリストされます。

  • "m"の代わりにthis->を使用できます。はい、できます。しかし、それは単なるmuchい、より冗長な接頭辞です!コンパイラーにとってはoptionalであるため、はるかに大きなリスク(特にチーム内)を伴うため、その使用法は頻繁に矛盾します。一方、mは簡潔で、明確で、明示的であり、オプションではないため、それを使用してミスを犯すのははるかに困難です。

222
Jason Williams

私は通常、メンバー変数にプレフィックスを使用しません。

「C++にはすでにメンバーアクセス用の標準プレフィックスがあります:this->」と誰かが指摘するまで、私はmプレフィックスを使用していました。

それが今私が使っていることです。つまり、あいまいさがある場合this->プレフィックスを追加しますが、通常はあいまいさはなく、変数名を直接参照できます。

私にとって、それは両方の世界の最高です。必要なときに使用できるプレフィックスがあり、可能な限り省略できます。

もちろん、これに対する明白なカウンターは「はい、しかし、変数がクラスメンバーであるかどうかが一目でわかりません」です。

私は「そうなの?それを知る必要があるなら、おそらくあなたのクラスは状態が多すぎます。あるいは、関数が大きすぎて複雑です」と言います。

実際には、これが非常にうまく機能することがわかりました。追加のボーナスとして、ローカル変数をクラスメンバーに昇格させることができます(またはその逆)。名前を変更する必要はありません。

そして何よりも、それは一貫しています!一貫性を維持するために、特別なことをしたり、規則を覚えたりする必要はありません。


ところで、あなたはshould n'tクラスのメンバーに先頭のアンダースコアを使用します。実装によって予約されている名前に不快なほど近くなります。

標準では、二重アンダースコアまたはアンダースコアの後に大文字が続くすべての名前が予約されています。また、単一のアンダースコアで始まるすべての名前を予約しますグローバル名前空間内

そのため、先頭にアンダースコアがあり、その後に小文字が続くクラスメンバーは有効ですが、遅かれ早かれ、大文字で始まる識別子に対して同じことを行うか、上記のルールのいずれかを破ることになります。

したがって、先頭のアンダースコアを回避する方が簡単です。変数名にスコープをエンコードする場合は、後置アンダースコアを使用するか、m_またはmプレフィックスを使用します。

106
jalf

私は、次のような後置アンダースコアを好む:

class Foo
{
   private:
      int bar_;

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

最近、私は接頭辞をまったく持たずにm_接頭辞を好む傾向があります。その理由は、メンバー変数にフラグを立てることが重要であるほどではありませんが、曖昧さを避けるためです。

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

原因の問題は機能せず、1つのfooのみが許可されます。オプションは次のとおりです。

  • this->foo = foo;

    パラメータのシャドーイングが発生するため、g++ -Wshadow警告を使用できなくなり、m_を入力する時間も長くなります。 int foo;int foo();がある場合、変数と関数の間で名前の競合が発生します。

  • foo = foo_;またはfoo = arg_foo;

    しばらくそれを使用していましたが、引数リストが見苦しくなりました。ドキュメントは実装の名前の曖昧さを処理してはいけません。ここには、変数と関数の名前の競合も存在します。

  • m_foo = foo;

    APIドキュメントはクリーンなままで、メンバー関数とメンバー変数のあいまいさはなく、this->よりも入力しやすいです。唯一の欠点は、POD構造が見苦しいことですが、POD構造はそもそも名前のあいまいさに悩まされないため、それらを使用する必要はありません。一意のプレフィックスがあると、いくつかの検索と置換の操作も簡単になります。

  • foo_ = foo;

    m_の利点のほとんどは適用されますが、審美的な理由でこれを拒否します。末尾または先頭のアンダースコアは、変数を不完全で不均衡に見せます。 m_の見た目が良くなりました。 m_を使用すると、グローバルにg_を使用し、静的にs_を使用できるため、拡張性も向上します。

PS:PythonまたはRubyにm_が表示されない理由は、両方の言語が独自のプレフィックスを適用するためです。Rubyはメンバー変数に@を使用し、 Pythonにはself.が必要です。

19
Grumbel

メンバー関数を読むとき、各変数の「所有者」を知ることは、変数の意味を理解するために絶対に不可欠です。このような関数では:

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

ハンガリー語doesコードについて何か新しいことを教えてください。 Foo :: bar()関数にはいくつかの暗黙的なキャストがあることがわかりました。現在のコードの問題は、ハンガリー語の接頭辞によって追加される情報の価値が視覚的コストに比べて小さいことです。 C++型システムには、型が適切に連携するのを助けるため、またはコンパイラの警告またはエラーを発生させるための多くの機能が含まれています。コンパイラは、型の処理を支援します。そのために表記をする必要はありません。 Foo :: bar()の変数はおそらく数値であると簡単に推測できます。それがすべてわかっていれば、関数の一般的な理解を得るのに十分です。したがって、各変数の正確なタイプを知ることの価値は比較的低いです。しかし、「s_dSpuds」(または単に「dSpuds」)のような変数のofさは素晴らしいです。したがって、費用便益分析はハンガリーの表記法を拒否しますが、g_、s_、およびm_の利点は多くのプログラマーの目には費用を圧倒します。

10
OldPeculier

私はそれがどれほど広いかは言えませんが、個人的に言えば、私は常に(そして常に)メンバー変数の前に 'm'を付けます。例えば。:

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

これは私が使用するプレフィックスの唯一の形式です(私は非常に反ハンガリー語の表記法です)が、長年にわたって私は良い立場に立っていました。余談ですが、アンダースコアを名前(または他の場所)で使用することは一般的に嫌いですが、通常はすべて大文字であるため、プリプロセッサマクロ名は例外にします。

10
anon

メンバープレフィックスの主な理由は、ローカルのメンバー関数と同じ名前のメンバー変数を区別するためです。これは、ものの名前でゲッターを使用する場合に便利です。

考慮してください:

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()に変更するか、何らかの方法でメンバー変数を修飾する必要があります。

7

読みやすさを改善する方法として、命名規則ではなくリファクタリングに焦点を当てた応答があります。一方が他方を置き換えることができるとは思わない。

私は、ローカル宣言を使用することに不快なプログラマを知っています。すべての宣言を(Cのように)ブロックの先頭に配置することを好むので、どこにあるかがわかります。スコーピングで許可されている場合、変数が最初に使用された場所で変数を宣言すると、宣言を見つけるために後方に目を向ける時間が短縮されることがわかりました。 (これは、小さな関数であっても当てはまります。)これにより、私が見ているコードを理解しやすくなります。

これがどのようにメンバーの命名規則に関係するかが十分に明確であることを願っています。宣言はソースファイルにも見つからないことを知っています。

私はこれらのスタイルを好むことから始めなかったと確信しています。しかし、時間が経つにつれて、それらが一貫して使用される環境で作業し、それらを利用するために思考を最適化しました。私は、現在彼らに不快感を抱いている多くの人々が、一貫した使用を考えると、彼らを好むようになる可能性があると思います。

6
Dan Breslau

ある構文が他の構文よりも本当の価値があるとは思わない。あなたが言及したように、それはすべてソースファイル全体の均一性に要約されます。

このようなルールが面白いと思う唯一のポイントは、同一の名前の2つのものが必要な場合です。

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

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

この2つを区別するために使用します。また、Windows Dllからのように呼び出しをラップすると、DllからのRecvPacket(...)がコード内でRecvPacket(...)にラップされる場合があります。これらの特定の状況では、「_」などのプレフィックスを使用すると、2つが似たものになり、どちらがどちらであるかを簡単に識別できますが、コンパイラーでは異なります。

6
Eric

他の人は、メンバー変数が使用されるたびにthis-> memberの使用を強制しようとします

通常、これはプレフィックスがないためです。コンパイラーは、問題の変数を解決するのに十分な情報を必要とします。これは、接頭辞のために一意の名前であるか、thisキーワードを使用するかによって異なります。

ですから、はい、プレフィックスはまだ有用だと思います。私は、たとえば、「this->」ではなく「_」と入力してメンバーにアクセスすることを好みます。

5
Kent Boogaart

これらの規則はまさにそれです。ほとんどの店では、コードの読みやすさを向上させるためにコード規則を使用しているため、誰でも簡単にコードを見て、パブリックメンバーとプライベートメンバーなどをすばやく解読できます。

5
Mr. Will

他の言語はコーディング規約を使用しますが、異なる傾向があります。たとえば、C#には、おそらく2つの異なるスタイルがあります。C++メソッド(_variable、mVariable、またはハンガリー語表記などの他のプレフィックス)のいずれか、またはStyleCopメソッドと呼ばれるものです。

private int privateMember;
public int PublicMember;

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

結局、それは人々が知っていること、そして最もよく見えるものになります。個人的には、コードはハンガリー語表記なしで読みやすいと思いますが、たとえばハンガリー語表記が添付されている場合、インテリセンスを使用して変数を見つけやすくなります。

上記の例では、メンバー変数に接頭辞mを使用する必要はありません。これは、使用法に接頭辞を付けるためです。コンパイラーによるメソッドで同じことを示します。

これは、必ずしも他の方法が悪いことを意味するものではなく、人々は何が機能するかに固執します。

4
Will Eddins

C++メンバー変数のプレフィックスの最初のアイデアは、コンパイラが知らなかった追加の型情報を保存することでした。したがって、たとえば、固定長の文字列と、変数で '\ 0'で終了する別の文字列を使用できます。コンパイラにとっては、両方ともchar *ですが、一方から他方にコピーしようとすると、大きな問題が発生します。だから、私の頭の上から、

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

ここで、「asz」はこの変数が「ascii文字列(ゼロ終了)」であることを意味し、「arr」はこの変数が文字配列であることを意味します。

その後、魔法が起こります。コンパイラは次のステートメントに完全に満足します。

strcpy(arrWilma, aszFred);

しかし、人間として、あなたはそれを見て、「ねえ、それらの変数は実際には同じ型ではない、私はそれができない」と言うことができます。

残念ながら、多くの場所では、メンバー変数に「m_」、使用方法に関係なく整数に「i」、文字ポインターに「cp」などの標準を使用しています。言い換えれば、彼らはコンパイラが知っていることを複製し、同時にコードを読みにくくしています。私は、この有害な慣行は法律によって禁止され、厳しい罰則の対象となると信じています。

最後に、言及しなければならない2つのポイントがあります。

  • C++機能の賢明な使用により、コンパイラは生のCスタイル変数でエンコードする必要がある情報を知ることができます。有効な操作のみを許可するクラスを作成できます。これは、できる限り実行する必要があります。
  • コードブロックが長すぎて、使用する前に変数の型を忘れた場合、それらはway長すぎます。名前を使用しないで、再編成します。
3
A. L. Flanagan

私たちのプロジェクトでは、常に「its」をメンバーデータのプレフィックスとして使用し、「the」をパラメーターのプレフィックスとして使用していますが、ローカルのプレフィックスはありません。それは少しかわいいですが、当時使用していたいくつかの商用ソースライブラリ(XVTまたはRogueWave-おそらく両方)の慣習として使用されているのを見て、システムの初期の開発者に採用されました。したがって、次のようになります。

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

スコーピングプレフィックスの最大の理由(ハンガリー語表記が嫌いです)は、ある変数を参照していると思われるコードを書くことで問題が発生するのを防ぎますが、実際には別の変数を参照していますローカルスコープで同じ名前が定義されています。また、上記の例のように、同じ概念を表す変数名を思い付くという問題を回避しますが、スコープが異なります。その場合は、とにかくパラメーター「theName」のプレフィックスまたは別の名前を考え出す必要があります。どこにでも適用される一貫したルールを作成してください。

This->を使用するだけでは十分ではありません。コーディングエラーを減らすことほど曖昧さを減らすことには興味がなく、ローカルスコープの識別子で名前をマスクするのは苦痛です。確かに、一部のコンパイラには、より大きなスコープで名前をマスクした場合に警告を発するオプションがありますが、たまたま選択したサードパーティライブラリの大規模なセットで作業している場合、それらの警告は迷惑になる可能性があります時々あなた自身のものと衝突する未使用の変数の名前。

その/それ自体について-私は正直にアンダースコアよりも入力しやすいと感じています(タッチタイピストとして、可能な限りアンダースコアを避けます-ホーム行から伸びすぎています)、そしてミステリアスなアンダースコアよりも読みやすいです。

3
Steve Broberg

すでに他の人が言っているように、重要なのは口語的である(あなたが書いているコードベースに命名スタイルと規則を適応させる)と一貫性があることです。

何年もの間、「this->」規則と、メンバー変数にpostfixアンダースコア表記法の両方を使用する大規模なコードベースに取り組んできました。何年もの間、私は小規模なプロジェクトにも取り組んできました。メンバー変数の命名規則がまったくないものと、メンバー変数の命名規則が異なるものがありました。これらの小規模なプロジェクトの中で、慣例に欠けているプロジェクトは、すぐに理解して理解するのが最も難しいことが一貫してわかっています。

私は命名について非常にアナルを保持しています。クラスまたは変数に起因する名前に苦心し、「良い」と感じるものを思い付かない場合は、無意味な名前を付け、実際にそれを説明するコメントを提供することを選択しますです。そうすれば、少なくとも名前は、私が意図するとおりの意味を意味します。それ以上でもそれ以下でもありません。そしてしばしば、しばらくそれを使用した後、名前が何をreallyであるべきかを発見し、戻って適切に変更またはリファクタリングすることができます。

作業を行うIDEのトピックに関する最後のポイント-それはすべて良いことですが、IDEは私が最も緊急の作業を行う環境では利用できないことがよくあります。時々、その時点で利用できる唯一のものは「vi」のコピーです。また、名前のスペルが間違っているなど、IDEコード補完が愚かさを広めている多くのケースを見てきました。したがって、IDE松葉杖に頼る必要はありません。

3
Chris Cleeland

大きなメソッドまたはコードブロックがある場合は、ローカル変数を使用するかメンバーを使用するかをすぐに知ると便利です。エラーを回避し、より明確にするためです!

3
Matthieu

IMO、これは個人的なものです。プレフィックスをまったく付けません。とにかく、コードがパブリックであることを意味する場合は、いくつかのプレフィックスを付ける方が良いと思うので、読みやすくすることができます。

多くの場合、大企業は独自の「開発者ルール」を使用しています。
ところで、私が見た中で一番おかしくて賢いのは、DRY KISS(自分を繰り返してはいけません。シンプルで愚かなことです)。 :-)

3

クラスメンバーとメンバー関数パラメーターおよびローカル変数を区別するためにプレフィックスが必要な場合、関数が大きすぎるか、変数の名前が間違っていると思います。画面に収まらないため、何が何であるかを簡単に確認できる場合は、リファクタリングします。

それらが頻繁に使用される場所から遠く離れて宣言されていることを考えると、グローバル定数(およびグローバル変数、IMOはほとんど使用する必要はほとんどありませんが)の命名規則が理にかなっています。しかし、そうでなければ、私は多くの必要性を見ていません。

そうは言っても、私はすべてのプライベートクラスメンバーの最後にアンダースコアを付けていました。私のデータはすべてプライベートであるため、これはメンバーの末尾にアンダースコアがあることを意味します。私は通常、これを新しいコードベースではもうしませんが、プログラマーとしてあなたは主に古いコードを扱うので、私はまだこれをたくさんします。この習慣に対する私の寛容は、私がいつもこれを常に行っていて、それを定期的に行っているという事実に由来するのか、それともメンバー変数のマーキングよりも意味があるのか​​どうかはわかりません。

2
sbi

pythonでは、先頭の二重アンダースコアがプライベートメンバーをエミュレートするために使用されます。詳細については、 この回答 を参照してください

2

VC++のIntellisenseは、クラスの外にアクセスするときにプライベートメンバーをいつ表示するかを判断できないため、これを使用します。唯一の表示は、Intellisenseリストのフィールドアイコンにある小さな「ロック」シンボルです。プライベートメンバー(フィールド)の識別が簡単になります。正直に言うと、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
Zack

メモリ管理のため、メンバー変数とローカル変数を区別すると便利です。大まかに言って、ヒープに割り当てられたメンバー変数はデストラクタで破棄する必要がありますが、ヒープに割り当てられたローカル変数はそのスコープ内で破棄する必要があります。メンバー変数に命名規則を適用すると、正しいメモリ管理が容易になります。

1
frankster

このようなプレフィックスは必要ありません。そのような接頭辞が利点を提供する場合、一般的にコーディングスタイルを修正する必要があり、コードが明確にならないようにするのは接頭辞ではありません。一般的な不良変数名には、「other」または「2」が含まれます。 mOtherであることを要求することでそれを修正するのではなく、その関数のコンテキストでその変数が何をしているのかを開発者に考えさせることで修正します。おそらく彼は、remoteSide、newValue、secondTestListener、またはそのスコープ内の何かを意味していました。

それは効果的な時代錯誤であり、まだあまりにも広まっています。変数に接頭辞を付けるのをやめ、変数に使用期間を明確に示す適切な名前を付けます。最大5行で、混乱なく「i」と呼ぶことができます。 50行を超えると、かなり長い名前が必要になります。

1
dascandy

変数名の前にプレフィックスを使用することはほとんどありません。まともなIDEを使用している場合は、リファクタリングして参照を簡単に見つけることができるはずです。私は非常に明確な名前を使用し、長い変数名を持つことを恐れていません。この哲学でも、スコープに問題はありませんでした。

プレフィックスを使用するのは、署名行のみです。メソッドのパラメーターの前に_を付けて、それらの周りに防御的にプログラムできるようにします。

1
James

私は、変数名に含まれる値に意味のみを与えるように変数名が好きで、名前から宣言/実装される方法を残します。値が意味するもの、期間を知りたい。おそらく平均以上のリファクタリングを行ったのかもしれませんが、名前に何かを実装する方法を組み込むと、リファクタリングが必要以上に退屈になります。オブジェクトメンバが宣言される場所または方法を示すプレフィックスは、実装固有です。

color = Red;

ほとんどの場合、Redが列挙型、構造体、その他のいずれであるかは気にしません。関数が非常に大きく、色がローカルで宣言されているかメンバーであるかを思い出せない場合は、おそらく中断する時間です関数をより小さな論理ユニットに分割します。

循環的な複雑さが非常に大きいため、実装固有の手がかりが物の名前に埋め込まれていないと、コードで何が起こっているかを追跡できない場合は、おそらく関数/メソッドの複雑さを軽減する必要があります。

ほとんどの場合、コンストラクタと初期化子でのみ「this」を使用します。

1
ChrisG65

Code Completeでは、メンバー変数にm_varnameを推奨しています。

M_表記が便利だとは思っていませんでしたが、標準を構築する際にMcConnellの意見を重視しました。

1
Paul Nathan

Intellisenseと関連するIDE機能を利用するためだけに、メンバー変数にm_を使用しています。クラスの実装をコーディングしているとき、m_と入力すると、すべてのm_メンバーがグループ化されたコンボボックスが表示されます。

もちろん、m_がなくても問題なく生活できます。私の仕事スタイルです。

0
Hernán

これらの規則の多くは、洗練された編集者がいない時代のものです。あらゆる種類の変数に色を付けることができる適切なIDEを使用することをお勧めします。色は、どの接頭辞よりもはるかに簡単です。

変数についてさらに詳細を取得する必要がある場合、現代のIDEは、キャレットまたはカーソルをその上に移動することで表示できます。また、間違った方法で変数を使用すると(たとえば、。演算子を使用したポインター)、エラーが発生します。

0
Elias Mueller

JOINT STRIKE FIGHTER AIR VEHICLE C++ CODING STANDARDS(2005年12月)によると:

AVルール67

パブリックデータと保護データは、クラスではなく構造体でのみ使用する必要があります。根拠:クラスは、データへのアクセスを制御することにより、不変式を維持できます。ただし、それらのメンバーがプライベートでない場合、クラスはそのメンバーへのアクセスを制御できません。したがって、クラス内のすべてのデータはプライベートである必要があります。

したがって、すべてのデータはプライベートである必要があるため、「m」プレフィックスは役に立たなくなります。

しかし、危険な変数であるため、ポインターの前にpプレフィックスを使用するのは良い習慣です。