[置頂]『C++高級進級』読書ノート第一章C++基礎知識

15444 ワード

1.2文字定数と定数
1、文字定数p 3
プログラム内の特殊な識別子または式は、(1)アドレス不可(コード領域に置く)(2)値が可変でないことを同時に満たすため、文字定数と見なすことができる.彼らは静的配列名、列挙変数、グローバル(静的変数)ヘッダアドレス、#define定義の定数である.
整数文字定数:(1)前に0を足すと8進(2)前に0を足すと16進(3)後にL(推奨)またはlを足す、longタイプ(4)後にU(またはu)を足すと符号なし数を表す
eg.1024UL
2、常変数Const
他の変数と同様に空間が割り当てられ、アドレス可能である.
constは高度な言語の意味レベルで定義され、コンパイラがコンパイル期間に文法検出を行うことで保証されていますが、実行時にconst変数は読み取り専用メモリではなく、一般的な変数と同じようにデータ領域に置かれるので、同じように修正できます.
したがって、常変数は特殊な制限を加えた変数であり、「読み取り専用」変数と理解される.
const修飾でも、修正できます
#include <iostream>
using namespace std;

void ShowValue(const int &i) {
    cout<<i<<endl;
}

int main() 
{
    const int j=5;
    void *p=(void *)&j;
    int *ptr=(int *)p;
    (*ptr)++;
    //cout<<j<<endl; //     5,           j       5
    //    int i=5; const int j=i;      ,    j 6
    ShowValue(j); //  6

    return 0; 
}

3、常変数置換
通常変数に初期化初期値がある場合、コンパイラはその通常変数を他の場所で文字定数に置き換えますが、初期化しないとエラーになります.
次のようになります.
void DefineArray(const int n){
     int B[n]={}; //error,          
}

int main(){
     const int m=5;
     int A[m]={}; //ok
}

4、文字定数と定数アドレス
int &r=5; //error,        ,      

const int &r=5; //ok,          5      ,     r        

1.3 constの使い方
1、constの位置
int const *p; //       (    ,const    int),      const ,     ,    p       
int *const p; //    (const    int*),    p const ,        ,           

constはデータ型と結合しています.->通常型.(全体として)
修飾タイプの場合は、前に置くことも、後ろに置くこともできます.定数宣言orで変数を定義し、constは変数の前にのみ表示されます.
constと被修飾タイプの間には、他の識別子は存在しません.
参照自体はポインタ定数として理解できます
だから引用する前にconstを使うのは意味がありません
int & const r4=i; //const    ,   warning   const  

constは二重ポインタを組み合わせ、この例ではconstは異なる位置にあり、結果は異なる.
#include <iostream>
using namespace std;

int main() 
{
    int const **p1; //      ,   int count*(“int const*”             )
    int *const *p2; //      ,           (int *const,          ,      )

    int i=5;
    int j=6;

    const int *ptr1=&i;
    int *const ptr2=&j;

    p1=&ptr1;
    p2=&ptr2;

    cout<<**p1<<endl;
    cout<<**p2<<endl;

    return 0; 
}

出力:5 6
上記p 1とp 2の付与にはこだわりがあり、p 1=&ptr 2またはp 2=ptr 1であればコンパイルエラー
2、const修飾クラス->常オブジェクトと常関数
const修飾オブジェクト->常オブジェクトconst修飾メンバー関数->常関数
定数関数では、メンバー変数の変更は許可されていません.
通常オブジェクトを使用すると、そのオブジェクトの通常関数のみが呼び出されます.
#include <iostream>
using namespace std;

class A
{
    int num;
public:
    A() {num=5;}
    void disp();
    void disp() const;
    void set(int n) {num=n;}

};

void A::disp() const {
    cout<<num<<endl;
}

void A::disp() {
    cout<<"non-const version of disp()"<<endl;
}

int main() 
{
    A a1;
    a1.set(3);
    a1.disp();
    A const a2;
    a2.disp();
}

以上の注意:(1)常関数の宣言と定義が分かれている場合はconstを追加する必要があります.そうしないとコンパイルエラーになります.
クラスの非静的メンバー関数のみを常関数として宣言できます
(2)クラスの2つのメンバー関数の場合、戻り値、関数名、パラメータリストが完全に同じで、そのうちの1つがconstである場合は再ロードされます.通常のメンバー関数のパラメータがthisポインタに入力されるのはconst Class*タイプであり、パラメータが異なるため、関数署名が異なります.
非読み取り専用オブジェクト(a 1など)は、disp()などの関数を呼び出し、非constバージョンを探し、ない場合はconstバージョンを呼び出します.通常オブジェクトは、クラスで定義された通常関数のみを呼び出すことができます.そうしないと、コンパイラはエラーを報告します.
a 1のような非constオブジェクトが関数を呼び出し、constバージョンと非constバージョンの関数がある場合、const関数を呼び出す必要があります.オブジェクトの通常参照を確立するか、オブジェクトへの通常ポインタを指して目的を達成する必要があります.例えば:(const A&)a 1.disp(); または(const A*)&a 1->disp();
(3)通常のオブジェクトが作成されると、そのデータメンバーは変更できません.したがって、コンストラクション関数を表示してオブジェクトを初期化することが重要です.
定数オブジェクトは、メンバーデータメンバー全員が定数視されます.クラスオブジェクトの非静的定数メンバーは、コンストラクション関数で初期化する必要があり、初期化リストでのみ実行できます.
3、const修飾関数パラメータ+関数戻り値
#include <iostream>
using namespace std;

void disp1(const int &ri){
    cout<<ri<<endl;
}

void disp2(const int i){
    cout<<i<<endl;
}

const int disp3(const int& ri){
    cout<<ri<<endl;
    return ri;
}

int& disp4(int& ri){
    cout<<ri<<endl;
    return ri;
}

const int& disp5(int& ri){
    cout<<ri<<endl;
    return ri;
}


int main(int argc,char* argv[])
{
    int n=5;
    disp1(n);
    disp2(n);
    disp3(n);
    disp4(n)=6; //       
    disp5(n);//disp5(n)=6;    
}

注意:(1)const修飾パラメータは、主な役割は参照されるオブジェクトまたは指向されるオブジェクトであり、パラメータだけではあまり意味がありません.例えば、void disp 2(const int i)では、ここでのiは関数で変更されず、constを追加するかどうかは影響しません.
それだけでなく、constでパラメータを修飾する関数とconstでパラメータを修飾しない関数を同時に定義すると、再定義エラーが発生します.たとえば、任意の整数式の値は、int型パラメータにもconst int型パラメータにも渡されるので、再ロードされません.
(2)戻り値が参照ではなく通常のデータである場合、const修飾もあまり意味がない.関数戻り値は非左値であるため、本来その値を変更することはできない.その上でconst int disp 3(const int&ri)は、戻り値を修飾している.
(3)戻り値が参照である場合、const修飾により被参照オブジェクトの修正を阻止することができ、disp 5(n)=6;間違いです
(4)よくあるconstに対する誤解.
誤解1:constで修正した変数値は必ず変更できない.const修飾の変数はポインタで間接的に変更できます.
次のようになります.
const int j=5;
void *p=(void *)&j;
int *ptr=(int *)p;
(*ptr)++;

誤解2:常引用または常ポインタは、常変数のみを指すことができ、これは大きな誤解である.常引用または常ポインタは、その参照(またはそのポインタ)によって参照されたオブジェクトを修正できないことを説明するだけであり、被引用オブジェクトの本来の性質は常引用(常ポインタ)によって決定できない.
1.4 const_castの使い方
1、作用
const_castはC++演算子であり、適合タイプのconstまたはvolatileを除去する役割を果たす.
const_を大量に使用するとcastは賢明ではなく,プログラムに設計欠陥があるとしか言いようがない.使用方法は次の例を参照してください.
void constTest(){
    int i;
    cout<<"please input a integer:";
    cin>>i;
    const int a=i;
    int& r=const_cast<int&>(a);//   int& r=a;       
    ++r;
    cout<<a<<endl;
}
int main(int argc,char* argv[])
{
    constTest();
    return 0;
}

入力:5
出力:6
まとめ:(1)const_cast演算子の構文形式はconst_cast(expression).かっこ省略不可
(2)const_castはターゲットのconstまたはvolatile属性のみを除去でき、異なるタイプの変換はできません.const type*をtype*に変換するか、const type&をtype&に変換するしかありません.次の変換はエラーです.
cons tint A={1,2,3}; 
char* p=const_cast< char*>(A); //   const int[]   char* 

(3)1つの変数が読取り専用変数(常変数)として定義されている場合、それは常に常変数である.cosnt_castは間接参照時の書き換え制限を取り消し、変数自体のconst属性を変更することはできない.以下はエラーである.
int j = const_cast< int> (i);

(4)従来のC言語の強制型変換ではconst type*タイプをtype*タイプに変換したり、const type&をtype&タイプに変換したりすることもできますが、const_castの書き方が複雑であるため、const_castを使用するとより良いでしょう.(プログラム猿は簡単に変換しないように注意します)、変換能力は弱くて、目的は明確で、間違いを犯しにくくて、バグを調べやすいです;Cスタイルの強制タイプの変換能力は強すぎて、リスクはわりに大きいです.
1.5 mutableの使い方
1、作用
mutableは、常関数でオブジェクトを変更できないデータメンバーの問題を解決するために使用されます.
場合によっては、定数関数でメンバー変数の値を変更したい場合は、その変数の前にmutableを追加します.定数オブジェクトのほとんどのデータ・メンバーが読み取り専用であることを保証する場合、個別のメンバーの変更を実現できます.
#include <iostream>
#include <string>
using namespace std;

class Student
{
    string Name; //   private
    int times_of_getname;
public:
    Student(char *name)
        :Name(name),times_of_getname(0) {

    }

    string get_name() {
        times_of_getname++;
        return Name;
    }

    void PrintTimes() const {
        cout<<times_of_getname<<endl;
    }
};

int main() 
{
    const Student s("Bill ");
    cout<<s.get_name()<<endl;
    cout<<s.get_name()<<endl;
    s.PrintTimes();

    return 0; 
}

定数オブジェクトs(情報が変更できない学生エンティティ)のため、const関数ではないget_name()が呼び出されますが、get_name()をconstに変更し、times_を変更できません.of_getname.
ただし、次のように変更します.
mutable int times_of_getname;

string get_name() const{
}

すぐ
2、使用上の注意
キーワードmutableを使用するには、次の点に注意してください.
(1)mutableはクラスの非静的および非常量のデータメンバーにのみ使用される.
(2)mutableキーワードプロンプトコンパイラこの変数はクラスのconst関数で変更できる.
(3)1つのクラスではmutableで修飾された変数は少数であるか,まったく使用されず,代表プログラム設計上の欠陥を大量に使用する.
1.6余剰演算子を求める
1、概要
%は剰余を求めるために使用され、優先度は*および/と同じであり、結合法則も左から右にある.
両方のオペランドが整数(または整数に暗黙的に変換できるタイプ)であることが要求されるため、doubleは整形に暗黙的に変換できないため、14.2%3がエラーです.
#include <iostream>
using namespace std;

int main() 
{
    char c=253;
    int i=5;
    cout<<c%2<<endl;
    cout<<i%c<<endl;
    cout<<19%10%5<<endl;

    return 0; 
}

出力:-12 4
c/c++では、charは単バイト整形と見なすことができ、値範囲-128~127をとることができるので、余剰を求めることに参加することができる.
253に対応するバイナリは0 xFD、すなわち-3の補符号表示であり、C 99標準規定:
%が正数である場合、a%(-b)==a%bがある.%左が負数の場合(-a)%b=-(a%b)
%は左から右へ結合しているため、19%10%5は(19%10)%5に相当し、結果は4