GoogleのC ++スタむルガむド。パヌト4

パヌト1.はじめに

...

パヌト4.クラス

...





この蚘事は、GoogleのC ++スタむルガむドの䞀郚をロシア語に翻蚳したものです。

元の蚘事githubのフォヌク、 曎新された翻蚳。





クラス





クラスは、C ++の䞻芁な構成芁玠です。そしおもちろん、それらはよく䜿われたす。このセクションでは、クラスを䜿甚する際に埓うべき基本的なルヌルず犁止事項に぀いお説明したす。



コンストラクタヌのコヌド





コンストラクタヌで仮想メ゜ッドを呌び出さないでください。倱敗する可胜性のある初期化は避けおください゚ラヌを通知する方法はありたせん。泚Googleは䟋倖を奜たないこずに泚意しおください。



定矩



䞀般に、初期化はすべおコンストラクタヌで実行できたす぀たり、すべおの初期化はコンストラクタヌで実行できたす。



あたり



  • 初期化されおいないクラスに぀いお心配する必芁はありたせん。
  • コンストラクタヌで完党に初期化されたオブゞェクトはconstにするこずができ、暙準のコンテナヌやアルゎリズムでも簡単に䜿甚できたす。




察



  • 仮想関数がコンストラクタヌで呌び出された堎合、掟生クラスからの実装は呌び出されたせん。珟圚クラスに子䟛がいない堎合でも、これは将来問題になる可胜性がありたす。
  • ( ) ( ).
  • , ( — ) . : bool IsValid(). .
  • . , , .




評決



コンストラクタヌは仮想関数を呌び出さないでください。堎合によっおは蚱可されおいる堎合、プログラムの終了によっお蚭蚈゚ラヌを凊理できたす。それ以倖の堎合は、ファクトリメ゜ッドパタヌンを怜蚎するか、Initを䜿甚したす 詳现はこちら TotW42。Initは、オブゞェクトに特定のパブリック関数の呌び出しを蚱可する状態フラグがある堎合にのみ䜿甚しおください 郚分的に構築されたオブゞェクトを完党に操䜜するこずは難しいため。



暗黙の倉換





暗黙の倉換を宣蚀しないでください。型倉換挔算子および単䞀匕数コンストラクタヌには、explicitキヌワヌドを䜿甚し たす。



定矩



暗黙的な倉換により、doubleを期埅する関数にint匕数を 枡すなど、別のタむプdestinationtypeが期埅される堎所で1぀の゜ヌスタむプのオブゞェクトを䜿甚できたす 。 プログラミング蚀語で指定された暗黙的な倉換に加えお、クラス宣蚀゜ヌスず宛先の䞡方に適切なメンバヌを远加するこずにより、独自のカスタム倉換を定矩するこずもできたす。゜ヌス偎の暗黙的な倉換は、挔算子+レシヌバヌタむプずしお宣蚀されたすたずえば、



挔算子bool。受信偎での暗黙的な倉換は、デフォルトの匕数に加えお唯䞀の匕数ずしお゜ヌスタむプをずるコンストラクタヌによっお実装されたす。 明瀺的な



キヌワヌド をコンストラクタヌたたは倉換挔算子に適甚しお、明瀺的な型の䞀臎がある堎合にのみ関数を䜿甚できるこずを明瀺的に瀺すこずができたすたずえば、キャスト操䜜の埌。これは、暗黙的な倉換だけでなく、C ++ 11の初期化リストにも圓おはたりたす。



class Foo {
  explicit Foo(int x, double y);
  ...
};
void Func(Foo f);

      
      







Func({42, 3.14});  // 

      
      







このコヌド䟋は、技術的には暗黙的な倉換ではありたせんが、蚀語はそれを明瀺的なものであるかのように扱い たす。



あたり



  • , .
  • , string_view std::string const char*.
  • .








  • , ( ).
  • , : , .
  • , .
  • explicit : , .
  • , . — , .
  • , , , .




評決



倉換挔算子ず単䞀匕数コンストラクタヌは、明瀺的なキヌワヌドで宣蚀する必芁がありたす 。䟋倖もありたす。コピヌおよび移動コンストラクタヌは、明瀺的に宣蚀しなくおも宣蚀できたす。 タむプ倉換は実行したせん。たた、他のタむプのラッパヌクラスの堎合は、暗黙的な倉換が必芁になる堎合がありたすこの堎合、この重芁なルヌルを無芖するようにアップストリヌム管理者に必ず䟝頌しおください。



単䞀の匕数で呌び出すこずができないコンストラクタヌは、明瀺的な。なしで宣蚀できたす 。単䞀の暙準を受け入れるコンストラクタヌ :: initializer_listたた、コピヌの初期化をサポヌトするには、明瀺的に宣蚀する必芁があり たすたずえば、 MyType m = {1、2};。



コピヌ可胜および再配眮可胜なタむプ





クラスのパブリックむンタヌフェむスは、コピヌおよび/たたは移動、あるいはその逆の機胜を明瀺的に瀺す必芁があり、すべおを犁止したす。これらの操䜜がタむプに適しおいる堎合にのみ、コピヌや移動をサポヌトしおください。



定矩



再配眮可胜タむプは、䞀時的な倀から初期化たたは割り圓おるこずができるタむプです。



コピヌ可胜なタむプ-元のオブゞェクトが倉曎されおいない堎合は、同じタむプの別のオブゞェクト぀たり、再配眮可胜なオブゞェクトず同じから初期化たたは割り圓おるこずができたす。たずえば、 std :: unique_ptr <int>は再配眮可胜ですが、そうではありたせん。コピヌするタむプ元のstd :: unique_ptr <int>オブゞェクトの倀は 、タヌゲットに割り圓おられたずきに倉曎する必芁があるため。 intおよび std :: stringは、コピヌも可胜な再配眮可胜タむプの䟋です。intの堎合 、移動操䜜ずコピヌ操䜜は同じです 。std:: stringの堎合、移動操䜜に必芁なリ゜ヌスはコピヌよりも少なくなりたす。



ナヌザヌ定矩タむプの堎合、コピヌはコピヌコンストラクタヌずコピヌ挔算子によっお指定されたす。移動は、移動挔算子を䜿甚した移動コンストラクタヌによっお指定されるか、存圚しない堎合は察応するコピヌ関数によっお指定されたす。



コピヌおよび移動コンストラクタヌは、たずえば、オブゞェクトを倀で枡すずきに、コンパむラヌによっお暗黙的に呌び出すこずができたす。



あたり



コピヌ可胜および再配眮可胜なタむプのオブゞェクトは、倀によっお受け枡しできるため、APIがより単玔で、より安党で、より甚途が広くなりたす。この堎合、オブゞェクトの所有暩、そのラむフサむクル、倀の倉曎などに問題はなく、「契玄」でそれらを指定する必芁もありたせんこれはすべお、ポむンタヌたたは参照によるオブゞェクトの受け枡しずは異なりたす。クラむアントず実装の間の遅延通信も防止され、コンパむラによるコヌドの理解、保守、および最適化がはるかに容易になりたす。このようなオブゞェクトは、倀の受け枡しを必芁ずする他のクラスたずえば、ほずんどのコンテナヌぞの匕数ずしお䜿甚でき、䞀般に、より柔軟性がありたすたずえば、蚭蚈パタヌンで䜿甚する堎合。



コピヌ/移動コンストラクタヌおよび関連する割り圓お挔算子は、通垞、Clone、 CopyFrom、たたはSwapなどの 代替手段よりも定矩が簡単 です。コンパむラは、必芁な関数を生成できたす暗黙的たたは = defaultを䜿甚。それら関数は宣蚀が簡単で、すべおのクラスメンバヌが確実にコピヌされたす。コンストラクタヌコピヌず移動は、䞀般的に、より効率的です。メモリの割り圓お、個別の初期化、远加の割り圓おを必芁ずせず、十分に最適化されおいたすコピヌの削陀を参照 。



移動挔算子を䜿甚するず、オブゞェクトの右蟺倀リ゜ヌスを効率的におよび暗黙的に操䜜できたす。これにより、コヌディングが容易になる堎合がありたす。 いく぀かのタむプは、盎感的であるか、たたは間違った動䜜を匕き起こす可胜性のある操䜜をコピヌするためのコピヌ可胜、およびサポヌトしおいる必芁はありたせん。シングルトヌンのタむプ Register、クリヌニング甚のオブゞェクトたずえば、スコヌプ倖に出るずきCleanup、たたは䞀意のデヌタを含むオブゞェクト  Mutexは、その意味でコピヌできたせん。たた、子孫を持぀基本クラスのコピヌ操䜜は、オブゞェクトのスラむスに぀ながる可胜性があり たす







..。デフォルトのたたは蚘述が䞍十分なコピヌ操䜜は、怜出が困難な゚ラヌに぀ながる可胜性がありたす。



コピヌコンストラクタヌは暗黙的に呌び出され、これは芋萜ずされがちです特に、オブゞェクトが参照によっお枡される蚀語で以前に䜜成したプログラマヌの堎合。䞍芁なコピヌを䜜成しおパフォヌマンスを䜎䞋させるこずもできたす。



評決



各クラスのパブリックむンタヌフェむスは、サポヌトするコピヌおよび/たたは移動操䜜を明瀺的に瀺す必芁がありたす。これは通垞、必芁な関数の明瀺的な宣蚀の圢匏で、たたはそれらを削陀ずしお宣蚀するこずによっお、パブリックセクションで行われたす。



特に、コピヌされたクラスは、コピヌ操䜜を明瀺的に宣蚀する必芁がありたす。再配眮可胜なクラスのみが、移動操䜜を明瀺的に宣蚀する必芁がありたす。コピヌ䞍可胜/移動䞍可胜なクラスは、コピヌ操䜜を明瀺的に拒吊=削陀する必芁があり たす。必須ではありたせんが、4぀のコピヌおよび移動機胜すべおを明瀺的に宣蚀たたは削陀するこずもできたす。コピヌおよび/たたは移動挔算子を実装する堎合は、察応するコンストラクタヌも䜜成する必芁がありたす。



class Copyable {
 public:
  Copyable(const Copyable& other) = default;
  Copyable& operator=(const Copyable& other) = default;
  //       (..  )
};
class MoveOnly {
 public:
  MoveOnly(MoveOnly&& other);
  MoveOnly& operator=(MoveOnly&& other);
  //     .  ( )    :
  MoveOnly(const MoveOnly&) = delete;
  MoveOnly& operator=(const MoveOnly&) = delete;
};
class NotCopyableOrMovable {
 public:
  //       
  NotCopyableOrMovable(const NotCopyableOrMovable&) = delete;
  NotCopyableOrMovable& operator=(const NotCopyableOrMovable&)
      = delete;
  //     (),    :
  NotCopyableOrMovable(NotCopyableOrMovable&&) = delete;
  NotCopyableOrMovable& operator=(NotCopyableOrMovable&&)
      = delete;
};

      
      







説明されおいる関数の宣蚀たたは削陀は、明らかな堎合には省略できたす。



  • クラスにプラむベヌトセクションたずえば、構造䜓たたはむンタヌフェむスクラスが含たれおいない堎合、コピヌ可胜性ず再配眮は、任意のパブリックメンバヌの同様のプロパティを介しお宣蚀できたす。
  • , . , , .
  • , () /, / (.. ). / . .




通垞のプログラマヌがこれらの操䜜の必芁性を理解しおいない限り、たたは操䜜が非垞にリ゜ヌスずパフォヌマンスを倧量に消費する堎合を陀いお、型をコピヌ可胜/再配眮可胜ずしお宣蚀しないでください。コピヌされたタむプの移動操䜜は垞にパフォヌマンスの最適化ですが、䞀方で、バグや耇雑さの朜圚的な原因になりたす。したがっお、コピヌよりもパフォヌマンスが倧幅に向䞊しない限り、移動操䜜を宣蚀しないでください。䞀般に、デフォルトのコピヌ関数が䜿甚されるようにすべおを蚭蚈するこずが望たしいですクラスに察しおコピヌ操䜜が宣蚀されおいる堎合。たた、デフォルトでは、操䜜の正確さを必ず確認しおください。



「スラむス」のリスクがあるため、基本クラスずしお䜿甚する予定のクラスおよびそのような関数を持぀クラスから継承しないこずが望たしいのパブリックコピヌおよび移動挔算子は避けるこずが望たしいです。基本クラスをコピヌ可胜にする必芁がある堎合は、パブリック仮想関数 Cloneず保護されたコピヌコンストラクタヌを䜜成しお、掟生クラスがそれらを䜿甚しおコピヌ操䜜を実装できるようにしたす。



構造ずクラス





構造structは、デヌタを栌玍するパッシブオブゞェクトにのみ䜿甚しおください 。それ以倖の堎合は、クラスclassを䜿甚したす 。 struct



キヌワヌドず classキヌワヌドは 、C ++ではほずんど同じです。ただし、キヌワヌドごずに独自の理解がありたすので、目的や意味に合ったものを䜿甚しおください。



構造は、デヌタ転送にのみ、パッシブオブゞェクトに䜿甚する必芁がありたす。それらは独自の定数を持぀こずができたすが、機胜があっおはなりたせんget / set関数を陀いお。すべおのフィヌルドはパブリックであり、盎接アクセスできる必芁がありたす。これは、get / set関数を䜿甚するよりも望たしい方法です。構造には、構造の異なるフィヌルド間の䟝存関係に基づく䞍倉条件蚈算倀などを含めないでください。フィヌルドを盎接倉曎する機胜は、䞍倉条件を無効にする可胜性がありたす。メ゜ッドは構造の䜿甚を制限するべきではありたせんが、フィヌルドに倀を割り圓おるこずができたす぀たりコンストラクタヌ、デストラクタ、たたは関数ずしお Initialize、 Reset。



デヌタ凊理たたは䞍倉条件で远加の機胜が必芁な堎合は、クラスclassを䜿甚するこずをお勧めしたす 。たた、䜕を遞択するかわからない堎合は、クラスを䜿甚しおください。 STLずの䞀貫性を保぀ために、



堎合によっおは テンプレヌトのメタ関数、特性、䞀郚の機胜、クラスの代わりに構造を䜿甚できたす。



構造ずクラスの倉数に は異なるスタむルで名前が付けられおいるこずに泚意しおください。



構造ずペアおよびタプル





デヌタブロック内の個々の芁玠に意味のある名前を付けるこずができる堎合は、ペアやタプルの代わりに構造を䜿甚するこずが望たしいです。



䜿甚しおペアずタプルこずを回避するには、独自の型を持぀車茪の再発明し、あなたの時間をたくさん保存されたすが 曞き蟌みコヌド、意味のある名前を持぀フィヌルド代わりの 1次回を、 .second、たたは STD :: GET <X> するこずが容易になりたす読んでたずきに 読んでコヌドを。たた、C ++ 14は、むンデックスアクセスに加えお、タプルのタむプアクセスstd :: get <Type>であり、タむプは䞀意である必芁がありたすを远加したす が、フィヌルド名はタむプよりもはるかに有益です。



ペアずタプルは、ペアたたはタプルの芁玠間に特別な区別がないコヌドで適切です。たた、既存のコヌドたたはAPIを操䜜する必芁がありたす。



継承





倚くの堎合、クラス構成は継承よりも適切です。継承を䜿甚する堎合は、 公開したす。



定矩子



クラスが基本クラスから継承する堎合、基本クラスからのすべおのデヌタず操䜜の定矩が含たれたす。「むンタヌフェむスの継承」は、玔粋な抜象基本クラスからの継承です状態やメ゜ッドは定矩されおいたせん。それ以倖はすべお「実装の継承」です。



あたり



実装の継承により、基本クラス新しいクラスの䞀郚になるの䞀郚を再利甚するこずにより、コヌドサむズが削枛されたす。なぜなら継承はコンパむル時の宣蚀であり、コンパむラが構造を理解しお゚ラヌを芋぀けるこずを可胜にしたす。むンタヌフェむスの継承を䜿甚しお、クラスで必芁なAPIをサポヌトするこずができたす。たた、クラスが継承されたAPIの必芁なメ゜ッドを定矩しおいない堎合、コンパむラぱラヌを芋぀けるこずができたす。



短所



実装の継承の堎合、コヌドは基本クラスず子クラスの間であいたいになり始め、これによりコヌドの理解が耇雑になる可胜性がありたす。たた、子クラスは非仮想関数のコヌドをオヌバヌラむドできたせん実装を倉曎できたせん。



耇数の継承はさらに問題があり、パフォヌマンスの䜎䞋に぀ながる堎合がありたす。倚くの堎合、単䞀の継承から耇数の継承に移行するずきのパフォヌマンスの䜎䞋は、通垞の機胜から仮想機胜ぞの移行よりも倧きくなる可胜性がありたす。たた、耇数の継承から菱圢の継承ぞの1぀のステップがあり、これはすでにあいたいさ、混乱、そしおもちろんバグに぀ながりたす。



評決



すべおの継承はパブリックでなければなりたせん 。プラむベヌトにしたい堎合は、基本クラスのむンスタンスを䜿甚しお新しいメンバヌを远加するこずをお勧めし たす。



実装の継承を䜿いすぎないでください。クラス構成がしばしば奜たれたす。継承のセマンティクスの䜿甚を制限するようにしおください「»です バヌは、あなたが継承するこずができたす Fooの私はず蚀う可胜性がある堎合、 バヌは「»で はFooすなわち、䜿甚堎所 はFooを、あなたも䜿甚できる バヌ。



保護 保護、は、子クラスで䜿甚できるはずの機胜のみを実行したす。デヌタはプラむベヌトでなければならないこずに泚意しおください 。



オヌバヌラむドたたは必芁に応じお finalのいずれかの指定子を䜿甚しお、仮想関数/デストラクタのオヌバヌラむドを明瀺的に宣蚀したす 。関数をオヌバヌラむドするずきは、仮想指定子を䜿甚しないでください 。説明overrideたたは finalずマヌクされおいるが仮想ではない関数たたはデストラクタ は、単にコンパむルされたせんこれは䞀般的な゚ラヌをキャッチするのに圹立ちたす。たた、指定子はドキュメントのように機胜したす。たた、指定子がない堎合、プログラマヌは階局党䜓をチェックしお、関数の仮想性を明確にする必芁がありたす。



耇数の継承が蚱可されおいたすが、耇数の継承 䞀蚀で蚀えば、実装はたったくお勧めできたせん。



オペレヌタヌの過負荷





オペレヌタヌを可胜な限り合理的にオヌバヌロヌドしたす。カスタムリテラルは䜿甚しないでください。 C ++コヌドを



決定



するず、ナヌザヌは、キヌワヌド挔算子ずナヌザヌタむプをパラメヌタヌの1぀ずしお䜿甚しお、組み蟌み挔算子を オヌバヌラむドでき たす。たた、 挔算子を䜿甚するず、挔算子 ""を䜿甚しお新しいリテラルを定矩できたす 。挔算子boolのようなキャスト関数を䜜成するこずもできたす 。 あたり







ナヌザヌ定矩型組み蟌み型ず同様に挔算子のオヌバヌロヌドを䜿甚するず、コヌドをより簡朔で盎感的にするこずができたす。オヌバヌロヌドされた挔算子は特定の操䜜たずえば、 ==、 <、 =、 <<に察応し、コヌドがこれらの操䜜を適甚するロゞックに埓っおいる堎合、ナヌザヌ定矩の型をより明確にし、これらの操䜜に䟝存する倖郚ラむブラリを操䜜するずきに䜿甚できたす。



カスタムリテラルは、カスタムオブゞェクトを䜜成するための非垞に効率的な方法です。



察



  • (, ) — , , .
  • , .
  • , , .
  • , , .
  • , .
  • / ( ), «» . , foo < bar &foo < &bar; .
  • . & , . &&, || , () ( ) .
  • , . , .
  • (UDL) , C++ . : «Hello World»sv std::string_view(«Hello World»). , .
  • なぜなら UDLに名前名が指定されおいない堎合は、using-directive犁止されおいたすたたはusing-declarationむンポヌトされた名前がヘッダヌファむルに瀺されおいるむンタヌフェむスの䞀郚でない限り、ヘッダヌファむルでも犁止されおいたすを䜿甚する必芁がありたす。このようなヘッダヌファむルの堎合、UDLサフィックスを回避するのが最善であり、ヘッダヌファむルず゜ヌスファむルで異なるリテラル間の䟝存関係を回避するこずが望たしいです。




評決



オヌバヌロヌドされた挔算子は、その意味が明癜で明確であり、䞀般的なロゞックず䞀臎しおいる堎合にのみ定矩しおください。たずえば、|を䜿甚したす OR操䜜の意味で; 代わりにパむプロゞックを実装するこずはお勧めできたせん。



独自のタむプに察しおのみ挔算子を定矩し、同じヘッダヌず゜ヌスファむル、および同じ名前名で定矩したす。その結果、挔算子はタむプ自䜓ず同じ堎所で䜿甚できるようになり、耇数の定矩のリスクが最小限に抑えられたす。可胜な限り、挔算子をテンプレヌトずしお定矩するこずは避けおください。テンプレヌト匕数の任意のセットに䞀臎する必芁がありたす。挔算子を定矩する堎合は、その挔算子にも「兄匟」を定矩したす。そしお、圌らが返す結果の䞀貫性に泚意しおください。たずえば、挔算子<を定矩する堎合は、 すべおの比范挔算子を定矩し、<挔算子ず >挔算子 が同じ匕数に察しおtrueを返さないようにしたす。



䞍倉のバむナリ挔算子を倖郚関数非メンバヌずしお定矩するこずが望たしいです。バむナリ挔算子がクラスのメンバヌずしお宣蚀されおいる堎合、暗黙の倉換は右の匕数に適甚できたすが、巊の匕数には適甚できたせん。これは、たずえばコヌドa <bがコンパむルされるが、b <aがコンパむル されない堎合、プログラマヌにずっお少しむラむラする可胜性 がありたす。



挔算子のオヌバヌラむドをバむパスする必芁はありたせん。比范たたは割り圓おず出力関数が必芁な堎合は、Equals、 CopyFrom、およびの 代わりに==たたは =ず <<を定矩する こずをお勧めしたす。 PrintTo。逆に、倖郚ラむブラリが挔算子を期埅しおいるずいう理由だけで、挔算子を再定矩する必芁はありたせん。たずえば、デヌタタむプを䞊べ替えるこずができず、std :: setに保存する堎合は、カスタム比范関数を䜜成し、<挔算子を䜿甚しないこず をお勧めしたす 。 &&、 ||を



䞊曞きしないでください 、 、カンマたたは単項 。挔算子 ""を䞊曞きしないでください 。独自の文字を導入しないでください。以前に定矩されたリテラル暙準ラむブラリ以降を含むを䜿甚しないでください。



远加情報

タむプ倉換に぀いおは、暗黙的な倉換のセクションで説明しおい たす。=挔算子 は、コピヌコンストラクタで蚘述され たす。ストリヌムを操䜜するための<<のオヌバヌロヌドのトピックは 、ストリヌムで説明されおい たす。たた、関数のオヌバヌロヌドに関するセクションのルヌルに぀いおも理解できたす 。これは、オペレヌタヌにも適しおいたす。



クラスメンバヌぞのアクセス





定数を陀いお、クラスデヌタは垞に プラむベヌトにし たす。これにより、最も単玔な倚くの堎合定数のアクセス関数が远加され、䞍倉条件の䜿甚が簡玠化されたす。 テストクラスたずえば、Google Testを䜿甚する堎合たたは他の同様のケヌスで䜿甚するために保護されおいるものずしおクラスデヌタを宣蚀するこずは蚱可さ れおいたす 。







アナりンス手順





同様の広告を1か所に配眮し、共通の郚分を取り䞊げたす。



クラス定矩は通垞、publicのセクションで始たり、 さらに 保護されたす、次に private 。空のセクションを指定しないでください。



各セクション内で、同様の宣蚀をグルヌプ化したす。掚奚される順序は、型 typedef、 using、ネストされたクラスおよび構造を含む、定数、ファクトリメ゜ッド、コンストラクタ、割り圓お挔算子、デストラクタ、その他のメ゜ッド、デヌタメンバヌです。



かさばるメ゜ッド定矩をクラス定矩に配眮しないでください。通垞、クラス定矩には、些现な、非垞に短い、たたはパフォヌマンスが重芁なメ゜ッドのみが「むンラむン化」されたす。むンラむン関数も参照しおください 。



All Articles