C++メモ(上)

8916 ワード

  • CとC++ポインタの最も重要な違いは、C++がより強い言語であることです.void *については、この点がより際立っている.Cは、1つのタイプのポインタを別のタイプに勝手に割り当てることは許されないが、void *によって実現することは許される.たとえば、
    bird* b;
    rock* r;
    void* v;
    v = r;
    b = v;
    C++では許可されていません.そのコンパイラはエラーメッセージを与えます.本当にそうしたい場合は、マッピングを明示的に使用し、コンパイラと読者に通知する必要があります.
  • パラメータ伝達準則関数にパラメータを伝達する場合、人々は定数参照によって伝達すべきである.この簡単な習慣は効率を大幅に向上させることができる.伝達方式は構造関数と構造関数を呼び出す必要があるが、パラメータを変更したくない場合は、定数参照によって伝達することができ、アドレスをスタックに圧縮するだけでよい.実際には、送信値が唯一の安全な方法である場合にのみ、オブジェクトが破壊されます(外部オブジェクトを変更するのではなく、呼び出し元が通常望んでいるものではありません).
  • C++アクセス権制御:public、private、protected protected protected継承にのみ異なる意味があります.そうしないとprivateと同じです.つまり、継承構造はprotectedメンバーにアクセスできますが、privateメンバーにアクセスできません.
  • 前置声明注意
    struct X;  // Declaration(incomplete type spec)
    struct Y
    {
      void f(X *memx);  
      void g(X memx);  // not allowed, the size of X is unknown.
    };
    ここでf(X*)はXオブジェクトのアドレスを参照しています.これは問題ありませんが、void g(X memx);ではだめです.コンパイラはエラーを報告します.コンパイラは、渡されたオブジェクトタイプのサイズにかかわらず、アドレスをどのように渡すかを知っているため、このアドレスのサイズは一定です.オブジェクト全体を転送しようとすると、コンパイラはXのすべての定義を知って、そのサイズとどのように転送するかを決定する必要があります.これにより、プログラマはY::g(X)のような関数を宣言できません.
  • C++は純粋ですか?クラスの関数がfriendと宣言された場合、クラスのメンバー関数ではありませんが、クラスのプライベートメンバーを変更でき、クラスの定義にリストされなければならないため、特権関数とみなすことができます.このクラスの定義は、クラスのプライベート部分を変更できる関数を知る権限に関する情報を提供します.したがって、C++は完全なオブジェクト向け言語ではなく、ハイブリッド製品にすぎません.friendキーワードは、部分的な突発的な問題を解決するために使用されます.この言語が不純であることも示しています.結局C++言語の設計は実用のためであり、理想の抽象を追求するのではない.
  • C++入出力ストリームのマニピュレータ演算子(manipulator)には、endl、flush、ws、hexなどがあります.
    cout<//       
    cout << hex << "0x" << i;  //   16     
    cin>>ws;  //     
    iostream.hはまた以下の操縦演算子を含む:どのように私たち自身の操縦演算子を創立しますか?私たちは自分の操作演算子を構築したいかもしれませんが、これはかなり簡単です.endlのようなパラメータを持たない操作演算子はただの関数であり、この関数はostreamをそのパラメータとして参照する.endlに対する宣言は、
    ostream& endl(ostream&);
    例です.このストリームをリフレッシュせずに改行を生成します.nlはendlを使用するよりも優れていると考えられています.後者は常に出力ストリームを空にしているため、実行障害を引き起こす可能性があります.
    ostream& nl(ostream& os) {
      return os << "
    "
    ; } int main() { cout << "newlines" << nl << "between" << nl << "each" << nl << "word" << nl; return 0; }
  • C言語におけるconstとC++におけるconstの違い:定数導入は初期のC++バージョンであり、当時標準C規範が制定されていた.その時、定数は良い思想と見なされてCに含まれていた.しかし、Cのconstは「変更できない一般的な変数」を意味し、Cでは常にストレージを占有し、名前はグローバルシンボルである.Cコンパイラはconstを1つのコンパイル期間の定数と見なすことができない.Cでは、
    const bufsize=100char buf[bufsize];
    と書くと、合理的なことをしたように見えますが、これは誤った結果を得ることになります.bufsizeはストレージの場所を占有するため、Cコンパイラはコンパイル時の値を知らない.C言語では、
    const bufsize;
    がC++に書かれているのは間違っていますが、Cコンパイラは、別の場所にストレージ割り当てがあることを示す宣言として使用します.Cデフォルトconstは外部接続なので、C++デフォルトcosntは内部接続です.このように、C++でCと同じことをしたい場合は、externで接続を外部接続に変更する必要があります.
    extern const bufsize;//declaration only
    という方法もC言語で使用できます.注意:C言語で制限子constを使用するのはあまり役に立ちません.定数式でも(コンパイル中に求めなければなりません).名前付きの値を使用するにはconstを使用してもあまり役に立ちません.Cプログラマにプリプロセッサでdefineを使用させる.
  • 類のconstとenumの次の書き方に何か問題がありますか.
    class bob {
        const size = 100;  // illegal
        int array[size];   // illegal
    }
    の結果はもちろんコンパイルに失敗しました.why?constはクラスオブジェクトに格納空間割り当てを行っているため,コンパイラはconstの内容が何であるかを知ることができないため,コンパイル期間の定数として使用することはできない.これはクラス内の定数式にとってconstがCのように機能しないことを意味する.クラス内のconstは「この特定のオブジェクトの寿命期間内で、クラス全体にとってこの値は変わらない」という意味です.では、定数式に使用できるクラス定数をどのように構築しますか?一般的な方法は、インスタンスを持たないタグのないenumを使用することです.列挙されたすべての値はコンパイル時に確立されなければならない.クラスにとってローカルであるが、定数式はその値を得ることができる.このように、
    class bob {
        enum { size = 100 };  // legal
        int array[size];      // legal
    }
    がenumを使用すると、オブジェクト内の記憶空間を占有することはなく、列挙定数はコンパイル時にすべて求められることが一般的に見られる.列挙定数の値:enum { one=1,two=2,three};
  • も明確に確立することができる.
  • クラスのconstメンバー関数
    class X {
        int i;
    public:
        int f() const;      
    }
    ここでf()はconstメンバー関数であり、constクラスオブジェクトのみがこの関数を呼び出すことができることを示します(constオブジェクトは非constメンバー関数を呼び出すことができません).オブジェクトのいずれかのメンバーを変更したり、非constメンバー関数を呼び出すと、コンパイラはエラーメッセージを発行します.キーワードconstは同じ方法で定義に繰り返し表示されなければなりません.そうしないと、コンパイラはそれを異なる関数と見なします.
    int X::f() const { return i;}
    メンバーデータを変更しない関数はconst関数として宣言され、constオブジェクトで使用できます.注意:コンストラクション関数とコンストラクション関数はconstメンバー関数ではありません.初期化とクリーンアップ時にオブジェクトが常に変更されるためです.

  • ###引用:constメンバー関数でメンバーを変更する方法--ビット単位とメンバー単位const####constメンバー関数を作成したい場合、オブジェクトでデータを変更したい場合はどうすればいいですか?これは、ビット別constとメンバー別constの違いに関係します.ビット別constは、オブジェクト内の各ビットが固定されているため、オブジェクトの各ビットイメージが変更されないことを意味します.メンバーconstでは、オブジェクト全体が概念的に変わらないが、あるメンバーが変化する可能性があるという意味です.コンパイラは、オブジェクトがconstオブジェクトであることを通知されると、そのオブジェクトを保護します.
    ここではconstメンバー関数でデータメンバーを変更する2つの方法について説明します.-1つ目の方法は、「強制変換const」と呼ばれる過去のものとなっている.かなり奇妙な方法で実行されます.this(このキーワードは現在のオブジェクトのアドレスを生成します)を取り、現在のタイプのオブジェクトへのポインタに強制的に変換します.これはすでに私たちが必要とするポインタのようですが、constポインタなので、演算で定数性を取り除くことができます.次に例を示します.
        class Y {
          int i, j;
        public:
          Y() { i = j = 0; }
          void f() const;
        };
    
        void Y::f() const {
        //!  i++;  // error
            ((Y*)this)->j++;  // ok , cast away const feature.
        }
           ,                 ,**         **。   :**this   const  ,               **,  ,           (           ),         。
    

    -2つ目の方法は、クラス宣言でキーワードmutableを使用して、特定のデータメンバーがconstオブジェクトで変更できることを指定する方法でもあります.
        class Y {
          int i;
          mutable int j;
        public:
          Y() { i = j = 0; }
          void f() const;
        };
    
        void Y::f() const {
        //!  i++;  // error
            ((Y*)this)->j++;  // ok , mutable.
        }
  • volatileキーワードvolatileの構文はconstと同じですが、volatileの意味は「コンパイラが認識する範囲外で、このデータは変更できます」です.なぜか、環境がデータを変更している(マルチタスクで処理される可能性がある)ため、volatileはコンパイラにデータに関する仮定を勝手にしないように伝えます.最適化の間、これは特に重要です.コンパイラが「私はすでにデータをレジスタに読み込み、レジスタと接触していない」と言ったら.一般的には、このデータを読む必要はありません.しかし、データがvolatileによって修飾されている場合、コンパイラは他のプロセスによって変更される可能性があるため、このコードを最適化するのではなく、このデータを再読みしなければならないと仮定することはできません.注意:
  • constオブジェクトを作成するように、プログラマーはvolatileオブジェクトを作成することもでき、const volatileオブジェクトを作成することもできます.このオブジェクトはプログラマーによって変更することはできませんが、外のツールで変更することができます.
  • constのように、データ・メンバー、メンバー関数、およびオブジェクト自体にvolatileを使用できます.volatileオブジェクトに対してvolatileメンバー関数を呼び出すこともできます.
  • volatileの文法はconstと同じなので、よく2つを一緒に議論します.2つのうちのいずれかを選択できることを表すために、2つはc-v限定語と呼ばれています.