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


150

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

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

他のメンバーは、メンバー変数が使用されるときはいつでもthis-> メンバーの使用を強制しようとします。

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

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

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


15
私はそれを好みます。複雑なコードベースでは、どのvarがローカルで、どれがローカルでないかを知ることが重要になる場合があります。私は通常、これを強制するのではなく接頭辞を使用します-これは、追加の入力が多く、オプションであることがわかります(名前を付けると強制されるためです)
Joe

5
属性の@と、属性を直接使用するよりもアクセサを生成する慣用法のため、Rubyではこれを見たことはありません。
スティーブジェソップ

6
PEP 8によると、非パブリックメンバー変数には、Pythonではアンダースコアが前に付けられます(例:)self._something = 1
Nathan Osman 2013

2
これらを識別するためにエディターの構文強調表示を使用すべきではありませんか?
あまりにも

2
this->memberPythonコードで同等のものを見たことがあります。Pythonでは通常そうでself.memberあり、それは慣例であるだけでなく、言語によって要求されます。
matec

回答:


48

先頭のアンダースコアの使用には注意が必要です。単語の大文字の前の先行アンダースコアは予約されています。例えば:

_フー

_L

すべて予約語ですが

_foo

_l

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

ローカル変数をマークアップすることの有用性について、私は垣間見ています。

次に、予約されている識別子に関するリンク を示します。C++識別子でアンダースコアを使用する場合のルールは何ですか?


4
実際には、_fooと_lの両方が名前空間スコープで予約されています。

13
ただし、メンバー変数名としては問題ありません。ルールが混乱しすぎて、私は過去に焦げていたので、アンダースコアにプレフィックスを付けません。
フアン

11
これらは予約語ではありません。それらは予約名です。予約語の場合は、まったく使用できません。これらは予約名であるため、使用できますが、自己責任で行ってください。
TonyK 2010年

235

私はすべて、プレフィックスがうまく機能していることを支持しています

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

この表記は、強く型付けされた言語、たとえばC ++ "lpsz"では、文字列がnulで終了する文字列への長いポインタであることを示すために、ほとんど意味がありません。 char配列。 "customerName"が文字列であることを知るのはそれほど難しくありません。

ただし、変数の使用法を指定するために接頭辞を使用します(本質的には「Appsハンガリー語」ですが、システムハンガリー語との関連が不適切で不公平であるため、ハンガリー語という用語は避けたいと思います)。これは非常に便利な時間節約であり、バグを減らすアプローチ。

私が使う:

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

タイプを明確にしたい場合は、標準のサフィックス(リスト、コンボボックスなど)を使用します。

これにより、プログラマーは変数を表示/使用するたびに変数の使用法を認識できます。間違いなく最も重要なケースは、ポインタの "p"です(使用法が変数から変数->に変更され、ポインタ(NULL、ポインタ演算など)についてはさらに注意する必要があるため)が、他のすべては非常に便利です。

たとえば、1つの関数で同じ変数名を複数の方法で使用できます(ここではC ++の例ですが、多くの言語に同じように適用されます)。

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

あなたはここで見ることができます:

  • メンバーとパラメーターの混同はありません
  • インデックス/イテレータとアイテムの間に混乱はありません
  • 「カウント」、「インデックス」などの一般的な(あいまいな)名前の多くの落とし穴を回避する、明確に関連する一連の変数(アイテムリスト、ポインタ、インデックス)の使用。
  • 接頭辞は、「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'と呼ばれるため、ポインターへのポインターです。

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

(仕事をするために上下に検索するのに時間を費やすと思わない場合は、1年前に作成し、それ以降見ていなかったコードを見つけてください。ファイルを開いて、読んでいない状態で半分ほど下にジャンプします。方法を見るメンバー、パラメーター、ローカルのいずれであるかが分からなくなる前に、この時点から読み取ることができます。次に、別のランダムな場所にジャンプします...これは、他の誰かのコードをシングルステップ実行しているときに、私たちが1日中行うすべてのことです。またはそれらの関数を呼び出す方法を理解しようとする)

接頭辞「m」は、(IMHO)の醜く冗長な「this->」表記、およびそれが保証する不整合も回避します(注意していても、通常は「this-> data」と名前の一貫したスペルを強制するものがないため、同じクラスの「データ」)。

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

最後の主な利点は、Intellisenseとオートコンプリートです。イベントを見つけるには、WindowsフォームでIntellisenseを使用してみてください。イベントを見つけるために呼び出す必要のない、何百もの神秘的な基本クラスメソッドをスクロールする必要があります。しかし、すべてのイベントに「e」という接頭辞が付いている場合、それらは自動的に「e」の下のグループにリストされます。したがって、プレフィックスを付けると、インテリセンスリストのメンバー、定数、イベントなどがグループ化され、必要な名前をすばやく簡単に見つけることができます。(通常、メソッドにはスコープ内でアクセス可能な約20〜50の値(ローカル、パラメーター、メンバー、定数、イベント)がある場合があります。ただし、接頭辞を入力した後(ここでインデックスを使用したいので、「i。 .. ')、2-5のオートコンプリートオプションのみが表示されます。

私は怠惰なプログラマーであり、上記の慣例は私に多くの仕事を節約します。すべての変数の使用方法を知っているので、コーディングを高速化でき、ミスを大幅に減らすことができます。


反対意見

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

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

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

  • 「接頭辞は私を混乱させる」。あなたがそれを使用する方法を学ぶまで、すべてのツールと同じように。脳が命名パターンに慣れると、情報が自動的に除外され、接頭辞がなくても問題ありません。しかし、本当に「流暢」になるには、このようなスキームを1〜2週間しっかりと使用する必要があります。そして、多くの人が古いコードを見て、優れた接頭辞スキームなしでどうやって管理したのか疑問に思い始めるときです。

  • 「私はこのことをうまく処理するためにコードを見ることができます」。はい。しかし、コードのどこか他の場所を調べたり、目がすでに集中しているその場で答えが正しい場合は、コードの細部をすべて覚えたりして時間を無駄にする必要はありません。

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

  • 「それはよりタイピングです」。本当に?もう一文字?またはそれは-IDEのオートコンプリートツールを使用すると、各プレフィックス文字によって検索スペースが大幅に狭まるため、入力が少なくなることがよくあります。「e」を押すと、クラスの3つのイベントがインテリセンスにポップアップ表示されます。「c」を押すと、5つの定数がリストされます。

  • " this->代わりに使えるm"。ええ、そうです。しかし、これは非常に醜く、より冗長な接頭辞です。コンパイラにとってそれはオプションであり、そのためその使用法はしばしば一貫性がないため、それだけが(特にチームで)はるかに大きなリスクを伴います。m一方、簡潔で明確、明示的であり、オプションではないため、それを使用して間違いを犯すことははるかに困難です。


6
私が読んだのは、ハンガリー語表記の問題がSimonyiの誤解のせいだということです。彼は、リテラルデータ型ではなく「種類」のように「型」を意味する変数の型を示すために、プレフィックスを使用するように記述しました。その後、Microsoftのプラットフォーム担当者がそれをピックアップしてlpszを思いついた...残りは履歴...
VoidPointer

19
「s is static」は私にとってハンガリー語の「悪い」形によく似ています。
jalf

6
@Mehrdad:zそのような低レベルの実装の詳細をクラスにカプセル化する必要があるC ++のような言語ではあまり役に立たないと思いますが、C(ゼロ終端が重要な区別である場合)では同意します。IMOで使用するスキームは、必要に応じて自分のニーズに合わせて調整する必要があります。つまり、ゼロ終端が変数の使用に影響を与える場合は、「z」をプレフィックスとして宣言しても問題はありません。
ジェイソンウィリアムズ

14
The most important case is "p" for pointer (because the usage changes from var. to var-> and you have to be much more careful with pointers.私は心から反対します。間違ったポインターを使用すると、コンパイルされません(void*ただし、ダブルポインターの例外になる場合があります)。そして、全体の->オーバーは.、それがポインタである私に言うには十分です。また、オートコンプリートを使用している場合は、おそらくエディターに宣言ツールチップがあり、変数情報のプレフィックスを付ける必要がなくなります。とにかく、良い答えです。
Thomas Eding

5
明確で包括的で興味深い説明に賛成ですが、これがC ++で時間を節約する方法を示唆することはほとんどありませんが、他の多くの言語ではほとんど未使用のままです。

115

通常、メンバー変数には接頭辞を使用しません。

m誰かが「C ++には既にメンバーアクセス用の標準の接頭辞がある:」と指摘するまで、私は接頭辞を使用していましたthis->

だから私は今それを使っています。つまり、あいまいな場合this->接頭辞を追加しますが、通常はあいまいさがなく、変数名を直接参照できます。

私にとって、それは両方の長所の1つです。必要なときに使用できる接頭辞があり、可能な限り省略できます。

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

私が言う「それで何?それを知る必要があるなら、あなたのクラスは多すぎる状態を持っているかもしれません。あるいは関数が大きすぎて複雑です」。

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

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


ちなみに、クラスメンバーには先頭のアンダースコアを使用しないでください。実装によって予約されている名前に不快に近くなります。

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

したがって、先頭にアンダースコアがあり、その後に小文字が続くクラスメンバーは合法ですが、遅かれ早かれ、大文字で始まる識別子に対して同じことを行うか、そうでなければ上記の規則の1つに違反します。

そのため、アンダースコアをリードしないようにする方が簡単です。変数名のスコープをエンコードする場合は、後置の下線、または接頭辞m_または単にm接頭辞を使用します。


「したがって、先頭にアンダースコアがあり、その後に小文字が続くクラスメンバーは合法ですが、遅かれ早かれ、大文字で始まる識別子に対して同じことを行うか、そうでなければ上記の規則の1つに違反します。」-クラスメンバー変数はグローバル名前空間にないため、その後に小文字または大文字が続くかどうかに関係なく、先頭のアンダースコアは安全です。
mbarnett 2011

3
@mbarnett:いいえ、アンダースコアとそれに続く大文字は、グローバル名前空間だけでなく、一般的に予約されています。
jalf

9
この回答の投票が前置投票より少ないことに驚きました。
Marson Mao

この回答に同意しthis->ます。メンバー変数を指定する必要がある場合にのみ使用してください。そうでない場合も同様です。
デビッドモートン2017年

さらに、コードを他の人に提供するために規則を文書化する必要はありません。誰もがthis->意味を理解しています。
Caduchon

34

私はそのようなポストフィックスアンダースコアを好む:

class Foo
{
   private:
      int bar_;

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

私も。アクセサー/ミューテーターにも同じ名前を付けます。
ロブ・

4
面白い。最初は少し醜く見えますが、それがどのように有益であるかを私は見ることができます。
ya23 2009年

6
「mBar」や「m_bar」よりもずっと醜くないと思います。
sydan 2015

6
しかし、あなたが持っていてvector<int> v_;、書くことv_.push_back(5)もかなり醜い
avim

4
これがGoogle C ++スタイルです。
Justme0 2015年

20

最近、私は接頭辞をまったく付けずにm_接頭辞を好む傾向があります。理由はそれほど多くありませんが、メンバー変数にフラグを付けることは重要ですが、あいまいさを避けるため、次のようなコードがあるとします。

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

原因は機能せず、foo許可されるのは1つだけです。だからあなたのオプションは:

  • 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_

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


1
公平を期すために、少なくとも2つの他のオプションを見逃しました。たとえば、(a)fooメンバーのみのようにフルネームを使用し、代わりにパラメーターやその他のローカル/スローウェイに単一文字または短い名前を使用しますint f。または(b)パラメータまたは他のローカルの前に何かを付けます。m_しかし、良い点とポッド。ほとんどの場合、私は独立して、両方のガイドラインに従うという好みに到達しました。
underscore_d

12

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

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」)のような変数の醜さは素晴らしいです。そう、


s_のアイデアをありがとう。とても便利なようで、どういうわけか私には思いつかなかった。
Chris Olsen

10

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

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

これは、私が使用する接頭辞の唯一の形式です(私は非常に反ハンガリー語の表記法です)が、何年にもわたって私をしっかりと支えてきました。余談ですが、私は通常、名前(またはそのほかの場所)でのアンダースコアの使用に反対していますが、通常はすべて大文字であるため、プリプロセッサマクロ名には例外を設けています。


5
m_(または_)ではなくmを使用する場合の問題は、キャメルケースの現在の方法にあり、一部の変数名を読み取ることが困難になります。
マーティンベケット

1
@ニール私はあなたと一緒です。@mgb:「_」で始まる名前は大嫌いです。これは、将来問題が発生する可能性があるためです。
マーティンヨーク

1
@ニール:アンダースコアを使用せず、キャメルケースを使用しない場合、どの規則を使用しますか?
jalf

2
私の理解では、「apData」のような変数にmだけを使用すると混乱するのはcamelCaseであり、「m_apData」ではなく「mapData」になります。_camelCaseは目立つため、保護された/プライベートなメンバー変数に使用します
Martin Beckett

10
@MartinBeckett:aそのシナリオではを大文字にする必要があります-それ以外の場合は正しく行いません。mApDatam接頭辞、変数名はapData)。
プラチナAzure

8

メンバー接頭辞の主な理由は、ローカルのメンバー関数と同じ名前のメンバー変数を区別するためです。これは、モノの名前でゲッターを使用する場合に役立ちます。

検討してください:

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


1
これが私が接頭辞を付ける理由です。私の意見foo.name()よりもずっと読みやすいと思いますfoo.get_name()
テラビット2016

6

ある構文が別の構文よりも価値があるとは思いません。あなたが言及したように、ソースファイル全体の均一性はすべて低下します。

私がそのようなルールを興味深いと思う唯一の点は、私が同一と名付けられた2つのものが必要なときです。例えば:

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

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

2つを区別するために使用します。また、私は、DLL、窓からのように、呼び出しをラップするときRecvPacket(...) DLLからはに包まれた可能性がありますRecvPacket(...)私のコードで。これらの特定の状況では、「_」のような接頭辞を使用すると、2つが同じように見え、どちらがどちらであるかを簡単に識別できますが、コンパイラでは異なります。


6

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

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

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

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


5

それらの慣習はそれだけです。ほとんどのショップでは、コード規則を使用してコードを読みやすくしているので、誰でも簡単にコードを見て、パブリックメンバーとプライベートメンバーなどをすばやく解読できます。


「パブリックメンバーとプライベートメンバーのようなもの」-これは本当にどれほど一般的ですか?私はそれを見たことを思い出しませんが、コードベースなどのレビューはしません。
underscore_d 2016年

私は自分のコーディングではそれをしていませんが、コードコンベンションガイドに基づいてそれを行わなければならない場所で働いていました。ほとんどすべてのIDEはプライベート変数を別の色で表示するので、私はそれをしないことを好みます。
ウィル氏2016年

うーん、それは私のものとは異なる状況でのみ起こると思います。通常、classすべてのメンバーがprivate/ であるes protected、またはstructすべての変数がすべてであるPOD を使用しますpublic(多くの場合はconst)。そのため、特定のメンバーのアクセスレベルを気にする必要はありません。
underscore_d 2016年

5

他のメンバーは、メンバー変数が使用されるときはいつでもthis-> memberの使用を強制しようとします

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

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


3
コンパイラはとにかくそれを解決できます...ローカル変数は、ほとんどの言語でより高いスコープの変数を非表示にします。コードを読む人間の(疑わしい)利益のためです。まともなIDEはローカル/メンバー/グローバルをさまざまな方法で強調表示するので、この種のものは必要ありません
rmeador

1
丁度。地元住民はクラスのメンバーを隠します。これらのメンバーを設定するコンストラクターを検討してください。通常、パラメーターにメンバーと同じ名前を付けることは意味があります。
ケントブーガート、2009

6
なぜコードのにおいがするのですか?特にコンストラクタに関しては、これは完全に一般的で合理的だと思います。
ケントブーガート、2009

3
コンストラクタは、初期化リストに(通常)ローカルを設定する必要があります。そして、パラメータはフィールド名をシャドウしませんが、どちらもアクセス可能です-だから、あなたは書くことができますstruct Foo { int x; Foo(int x) : x(x) { ... } };
Pavel Minaev

2
私はあなたが行うときに問題が来ると仮定しFoo(int x, bool blee) : x(x) { if (blee) x += bleecount; } // oops, forgot this->、私は彼らが名を省略一致するコンストラクタパラメータを便利な私のメンバ変数の何かを呼び出してから、与えることを好む:Foo(int f) : foo(f) {...}
スティーブ・ジェソップ

4

他の言語はコーディング規約を使用しますが、それらは異なる傾向があるだけです。たとえばC#には、C ++メソッドの1つ(_variable、mVariable、またはハンガリー語表記などの他の接頭辞)、または私がStyleCopメソッドと呼んでいるもののどちらかがよく使用される2つの異なるスタイルがあります。

private int privateMember;
public int PublicMember;

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

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

上記の例では、メンバー変数にmプレフィックスは必要ありません。これは、使用法の前にこれを付けるためです。コンパイラ強制メソッドで同じことを示します。

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


3

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


3
あなたが大きな方法を持っているなら、より明確にするためにそれを分解してください。
sbi 2009

4
いくつかの大きなメソッドを分解しない理由はたくさんあります。たとえば、メソッドが多くのローカル状態を保持する必要がある場合は、多数のパラメーターを下位のメソッドに渡すか、これらのメソッド間でデータを渡すためだけに存在する新しいクラスを作成するか、状態データを次のように宣言する必要があります。親クラスのメンバーデータ。これらすべてに、単一の長い方法(特に、ロジックが単純な方法)と比較して、メソッドの明快性または保守性に影響を与える問題があります。
Steve Broberg、

3
@sbi:ガイドラインはそれだけです。ルールではなくガイドライン。論理的に分割するのに適さない大きなメソッドが必要な場合や、パラメーター名がメンバーと競合する場合があります。
Ed S.

メンバー変数を公開しないでください。アクセサを使用するだけです。括弧は、それがメンバー変数であることを読者に伝えます。
jkeys 2009

注名前の衝突を検出するためのgccに警告(> = 4.6)が存在すること:-Wshadow
Caduchon

3

IMO、これは個人的なものです。接頭辞は一切付けていません。とにかく、コードが公開されるつもりなら、いくつかのプレフィックスを付けた方がいいので、読みやすくすることができます。

多くの場合、大企業は独自のいわゆる「開発者ルール」を使用しています。
ところで、私が見た中で最もおもしろくて賢いのは、DRY KISS(自分を繰り返さないでください。シンプルに、バカにしてください)でした。:-)


3

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

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

私はネーミングについて非常に肛門にこだわっています。私は、クラスまたは変数に起因する名前に苦労して、私が「良い」と感じるものを思い付かない場合は、無意味な名前を付け、それが本当に何であるかを説明するコメントを提供するようにしますです。このように、少なくとも名前は、私が意図していることを正確に意味しています。それ以上でもそれ以下でもありません。そして、多くの場合、しばらくそれを使用した後、名前が実際に何であるかを発見し、戻って適切に変更またはリファクタリングすることができます。

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


3

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」、charポインターには「cp」などの標準を使用しています。つまり、コンパイラが認識している内容を複製し、同時にコードを読みにくくしています。私はこの悪質な慣習は法律で非合法化されるべきであり、厳しい罰則の対象となるべきだと思います。

最後に、私が言及すべき2つのポイントがあります。

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

変数のタイプまたは種類を示すプレフィックスも議論に値するものですが、私は、何かが(プライベート)メンバー/フィールドであるかどうかを示すプレフィックスを主に参照していました。あなたが言及しているハンガリー語の逆表記は、インテリジェントに(例のように)適用すると非常に便利です。意味のある私のお気に入りの例は、相対座標と絶対座標です。absX = relXが表示されると、何かが間違っている可能性があることがはっきりとわかります。それに応じて関数に名前を付けることもできます。absX = absFromRel(relX、offset);
VoidPointer 2009

注:aszFredの初期化は疑わしい(リテラル文字列への非constアクセスを提供する)ため、arrWilmaの初期化はコンパイルすらできません。(おそらく、ポインタではなく配列としてarrWilmaを宣言するつもりでした!)ただし、頭の真上にあると書いたので問題ありません... :-)
Niels Dekker

おっと、あなたは完全に正しいです。子供たちは、家でそれを試さないでください。これを行う: 'const char * aszFred = "こんにちは、nullで終了する文字列です"; char arrWilma [] = {'O'、 'o'、 'p'、 's'}; '
ALフラナガン

3

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

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

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

this->を使用するだけでは十分ではありません。あいまいさを減らすことは、コーディングエラーを減らすことと同じくらい重要ではありません。また、ローカルスコープの識別子で名前をマスキングするのは簡単ではありません。確かに、一部のコンパイラは、より大きなスコープで名前をマスクした場合に警告を発するオプションを持っている場合がありますが、たまたま選択した多数のサードパーティライブラリを操作している場合、これらの警告は邪魔になることがあります。時々あなた自身のものと衝突する未使用の変数の名前。

その/それ自体について-正直に言うと、アンダースコアよりも入力する方が簡単だと思います(タッチタイピストとして、可能な場合は常にアンダースコアを避けます-ホームの行から離れすぎているため)。神秘的なアンダースコアよりも読みやすくなっています。


これは、私が今まで聞いた中で最も速い学習曲線を備えた最も直感的なソリューションです。コードのあいまいさを解決するための新しい手法を考え出す必要がないように、話し言葉言語がそれらすべてを処理するためのより柔軟であることを望みます。
Guney Ozsan 2016年

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

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

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

つまり、私はすべてのプライベートクラスメンバーの最後にアンダースコアを付けていました。私のデータはすべて非公開なので、これはメンバーに末尾の下線があることを意味します。私は通常、新しいコードベースではこれを実行しませんが、プログラマーとして、ほとんどの場合古いコードを使用するため、私はまだこれを頻繁に実行しています。この習慣に対する私の許容度が、いつもこれを行っていて、それを定期的に行っているという事実から来ているのか、それともメンバー変数のマーキングよりも意味があるのか​​わかりません。


2
これは私がこの問題について感じていることを非常に反映しています。コードは、接頭辞に頼らずに読みやすくする必要があります。最近の言語では、あまり多くの接頭辞が使用されていないようです。ユーザーコミュニティは、C ++で時々見られるものよりも読みやすさを受け入れているためです。もちろん、C ++は読み取り可能である必要があります。長年にわたって、多くの判読不能なC ++が作成されているだけです。
VoidPointer 2009


1

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


どうして?デストラクタは他の関数で宣言されたローカル変数にアクセスできないため、混乱する余地はありません。さらに、ヒープに割り当てられたローカル変数は存在すべきではありません。ヒープに割り当てられたメンバー変数は、RAIIクラス内にのみ存在する必要があります。
jalf

「ヒープに割り当てられたローカル変数は存在すべきではない」というのは少し強いです。ただし、それらを使用する場合、それらが適切に割り当て解除されることを確認することは非常に重要であるため、メンバー変数とローカル変数の規則正しい命名規則は、これを確実に支援します。
フランクスター2009

1

コード補完では、メンバー変数にm_varnameを推奨しています。

m_表記が役立つとは思っていませんでしたが、標準を構築する際にマックコンネルの意見を重視します。


2
彼がアンダースコアの理由を説明しない限り、そうではありません。私は何度もここで勧めた彼の "Rapid Development"の本の大ファンです。

1

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

接頭辞を使用するのは、署名欄のみです。メソッドのパラメータの前に_を付けるので、それらを防御的にプログラミングできます。


1

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

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


1

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

color = Red;

ほとんどの場合、私はRedが列挙型、構造体など何でもかまいません。関数が大きすぎて、カラーがローカルで宣言されているのか、メンバーであるのか思い出せない場合は、おそらく壊れる時間です関数を小さな論理ユニットに分割します。

サイクロマティックの複雑さが非常に大きいため、物事の名前に埋め込まれた実装固有の手掛かりがなければ、コードで何が起こっているのかを追跡できない場合、おそらく関数/メソッドの複雑さを減らす必要があります。

ほとんどの場合、コンストラクタとイニシャライザで「this」のみを使用します。


0

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

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


次のように入力することもできますthis->
トースト

0

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

AVルール67

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

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

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


0

それらの慣習の多くは、高度なエディターのない時代のものです。あらゆる種類の変数に色を付けることができる適切なIDEを使用することをお勧めします。色は、どの接頭辞よりもはるかに簡単に見つけることができます。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.