LotosLabo

プログラミング技術とか気になった情報を載せていきます

C++について7

メンバのアクセス制限


クラスの外から勝手にアクセス出来ないようなメンバ

privateメンバといいます。

class Car{
private:
int numl
double gas;
};


そうするとmain関数からはメンバにアクセスできなくなりました。

publicメンバ

例:

class Car{
   private:
    int num;
    double gas;
   public:
    void show();
    void setNumGas(int n, double g);
};

void Car:show()
{
    cout << "車のナンバーは" << num << "です\n";
    cout << "ガソリン量は" << gas << "です\n";
}
   
void Car::setNumGas(int n, double g)
{
   if(g > 0 && g < 1000){
    num = n;
    gas = g;
    cout << "ナンバーを" << num << "にガソリン量を" << gas << "にしました\n";
    }
    else{
     cout << g <<"は正しいガソリン量ではありません。\n";
     cout << "ガソリン量を変更できませんでした\n";
    }
 }

int main()
{
    Car car1;
    
    car1.SetNumGas(300,10.1);
    car1.show();
    
    cout << "正しくないガソリン量を(-10.0)を指定見ます\n";
    car1.SetNumGas(300,-10.0);
    car1.show(); 
    return 0;
}



publicメンバはクラスの外からもアクセスできます。


カプセル化


クラスの中にデータと機能をひとまとめにし、保護したいメンバにprivateをつけて勝手にアクセスできなくする機能をカプセル化と言います。

データメンバ → privateメンバ
メンバ関数 → publicメンバ

privateとpublicはアクセス指定子と呼ばれ、指定しない場合はすべてpublicとなります。

メンバ関数をインライン関数にする



privateメンバを呼び出すときにはpublicメンバ関数を呼び出してアクセスしなくてはなりません。その際に頻繁に呼び出されるので実行速度が遅くなってしまいます。そのためにインライン関数を使います。

class Car{
  private:
   int num;
   double gas;
  public:
   int getNum(){return num;}
   double getGas(){return gas;}
   void show();
   void setnumGas(int n, double g);
};
 
void Car::show()
{
  cout << "車のナンバーは" << num << "です\b";
}


クラス宣言内に関数本体を定義すると、自動的にインラインとしたことになる。

コンストラクタ

クラスからオブジェクトが作成されるときに、自動的に呼び出される。

クラス名::クラス名(引数のリスト)
{
}

Car::Car()
{
num = 0;
gas = 0.0;
cout << "車を作成しました。\n";
}

例:

class Car{
  private:
   int numl;
   double gas;
  public:
   Car();
   void show();
};
  
Car::Car()
{
  num = 0;
  gas = 0.0;
  cout << "車を作成しました\n";
}
  
void Car::show()
{
   cout << "車のナンバーは" << num << "です\n";
   cout << "ガソリン量は" << gas << "です\n";
}
  
int main()
{
    Car car1;
    car1.show();
    return 0;
}


出力結果


車を作成しました
車のナンバーは0です
ガソリン量は0です。


オブジェクトを初期化するために、コンストラクタを定義する。

コンストラクタオーバーロード



コンストラクタも引数の方や数が異なっていれば、同じようにオーバーロードをすることが出来ます。つまり、複数コンストラクタを定義することが出来ます。


例:

// 引数のないコンストラクタ
 
Car::Car()
{
 num = 0;
 gas = 0.0;
 cout << "車を作成しました\n";
}


// 引数のあるコンストラクタ
Car::Car(int n, double g)
{
   num = n;
   gas = g;
   cout << "ナンバー" << num << "ガソリン量" << gas << "の車を作成しました\n";
}




コンストラクタを省略すると、デフォルトコンストラクタが呼びだされます。

静的メンバ


各オブジェクトごとにデータメンバに値を格納する事ができた。
→ オブジェクトに関連付けられている。

しかし、オブジェクトに関連付けられていないメンバを持つことが出来ます。
それをクラス全体に関連付けられている。ということがあり、これを静的メンバといいます。


例:

// Carクラスの宣言
class Car{
  private:
   int num;
   double gas;
  public:
   static int sum; // 静的データメンバ
   Car();
   void setCar(int n, double g);
   void show();
   static void showSum(); // 静的メンバ関数
};
  
// Carクラスメンバ関数の定義
Car::Car()
{
//コンストラクタが呼び出された時に静的データメンバsumの値を1増やします。
   num = 0;
   gas = 0.0;
   sum++;
   cout << "車を作成しました\n";
}
  
void Car:setCar(int n, double g)
{
  num = n;
  gas = g;
  cout << "ナンバーを" << num << "にガソリン量を" << gas << "にしました\n";
}
 
//静的メンバ関数の定義
void Car::showSum()
{
  cout << "車を全部で" << sum << "台あります\n";
}
 
void Car::show()
{
  cout << "車のナンバーは" << num << "です\n";
  cout << "ガソリン量は" << gas << "です\n";
}
 
int Car::sum = 0; //静的データメンバを初期化します
 
int main(9
{
 // 静的データメンバ関数を呼び出す
  Car::showSum();
  
  Car car1; // オブジェクトを作成
  car1.setCar(300,10.1);
  
  Car::showSum(); // もう一度静的メンバ関数を呼び出す
  
  Car car2;
  car2/setCar(400,20.1);
  
  Car::showSum();
  
  return 0;
}


継承


元のクラスから新しいクラスを作成することをクラスを派生するといい、新しく拡張したクラスが既存のクラスのメンバを受け継ぐことを継承と言います。
また、元になる既存のクラスは基本クラス、新しいクラスは派生クラスと言います。

class 車{
ナンバー;
ガソリン量;
ナンバーとガソリン量を表示する機能
};

class レーシングカー:車{
競技用コース;
競技用コースを表示する機能

};

クラスを拡張する


class 派生クラス名 : アクセス指定子 基本クラス名
{
派生クラスに追加するメンバの宣言
};


例:

// 派生クラスの宣言
 class RacingCar : public Car{
   private:
  // 追加するデータメンバ
   int course;
   public:
  // 派生クラスのコンストラクタ
    RacingCar();
    //追加するメンバ関数
    void setCourse(int c);
};




メンバへのアクセス


派生クラスから基本クラスのメンバにアクセスする場合

protected アクセス修飾子を使います。

class Car{
  protected:
   int num;
   double gas;
  public:
   Car();
   void setCar(int m, double g);
   void show();
};



protectedメンバはprivateメンバと同様に外部からアクセスすることが出来ません。しかし、privateと異なり、派生クラスの内部からだけはアクセスできます。

仮想関数



基本クラスとまったく同じ関数名・引数の数・型をもつメンバ関数を定義することが出来ます。


void Car::show()
{
処理
}

void RacingCar::show()
{
処理
}

基本クラスのshow関数と派生クラスのshow関数が使われています。

派生クラスで定義したメンバ関数が、基本クラスのメンバに代わって機能することをオーバーライドといいます。

仮想関数の定義


仮想関数は基本クラスへのポインタを使って派生クラスのオブジェクトを扱う場合に使用します。

virtual 基本クラスメンバ関数の宣言;

class Car{
  protected:
   int num;
   double gas;
  public:
   Car();
   void setCar(int n, double g);
   virtual void show();  // 仮想関数
}




抽象クラス

virtual メンバ関数の宣言 = 0;

そして、クラスの宣言内にこのような関数を一つでも持つクラスは、オブジェクトを作成することが出来ないということになっています。このようなクラスを抽象クラスといいます。

オブジェクトのクラスを調べる

1つの抽象クラスによって、複数の派生クラスのオブジェクトを扱う場合があります。この時にオブジェクトのクラスを調べる事ができれば便利です。

このために実行時情報と呼ばれる情報を利用します。typeid演算子という機能を使います。

クラスの階層


派生クラスに対して直接的に基本クラスとなっている基本クラスを直接基本クラス、間接的に基本クラスとなっている基本クラスを関節基本クラスという。

多重継承


クラスを派生するときに、2つ以上のクラスを継承した派生クラスを使うことを多重継承と言います。

class 派生クラス : アクセス指定子 基本クラス1, アクセス指定子 基本クラス2・・{
}

また、多重継承した基本クラスのメンバが同じ名前の時はスコープを使って指定します。

演算子オーバーロード

オブジェクトを扱う演算子を新しく定義することを演算子オーバーロード言います。


メンバ関数としてオーバーロードする


operator 演算子記号()

p1 + p2という演算を行うと考えると

p1 .operator+ (p2);

p1というオブジェクトのoperator+()というメンバ関数を呼び出すことになる。
この関数を演算子関数とも言います。