ぼんさい塾

ぼんさいノートと補遺に関する素材や注釈です.ミスが多いので初稿から1週間を経た重要な修正のみ最終更新日を残しています.

Cから見たC++ (3)

2010-10-11 18:21:08 | 暮らし
記事一覧(Cの文法(1)~(17),他)
まず覚えるCの文法(progC.pdf)

P2.h: 段級位の追加
//-------------------------------------
#include "P1.h"
typedef struct{
  int id, dan;
} member2;
class group2 : public group{
private:
  member2 *top2;
  int dan;
public:
  group2(member*, int, member2*);
  void set_dan(int, int);
  void show(int);
  void add(int, char*, char*, int);
  void del(int);
};
group2::group2(
  member *p, int m, member2 *p2
):group(p, m){
  top2=p2;
}
void group2::set_dan(int i, int d){
  member *p=addr(i);
  top2[k].id=i; top2[k].dan=d;
}
void group2::show(int i){
  group::show(i);
  if(top[k].id==top2[k].id){
    printf("%d, %d\n",
           top[k].id, top2[k].dan);
  }else{printf("?\n");}
}
void group2::add(
  int i, char *n, char *m, int d
){
  group::add(i, n, m); set_dan(i, d);
}
void group2::del(int i){
  member *p=addr(0);
  member2 *q=&top2[k-1];
  group::del(i); p=addr(q->id);
  if(p->id==q->id){
    top2[k].id=q->id;
    top2[k].dan=q->dan; q->id=0;
  }
}
//-------------------------------------

P2.cpp: 使用例
//-------------------------------------
#include "P2.h"
member igo[10]={
  {1, "Aoki", "aoki@xxx.ne.jp"},
  {2, "Itoh", "taro@yyy.jp"},
};
member2 igo2[10]={{1, 2}, {2, -1}};
int main(void){
  member *p=&igo[0], *q;
  member2 *p2=&igo2[0];
  group2 g_igo2(p, 10, p2);
  g_igo2.add(5, "Tanaka",
            "foo@zzz.ac.jp", 0);
  for(q=p; q->id!=0; q++){
    g_igo2.show(q->id);
  }
  g_igo2.set_dan(5, 3); g_igo2.del(2);
  for(q=p; q->id!=0; q++){
    g_igo2.show(q->id);
  }
  return 0;
}
//-------------------------------------

=================================================
2. 派生クラス

囲碁,将棋に限らず柔道,剣道,書道,珠算等にも段
級位があります.2段を 2,3級を -3,不明を 0 と
した段級位のデータを扱えるように, group を拡張し
た派生クラス group2 の例を P2.h に示します.
(1)「class group2 : public group」は group から
   派生させることを意味します.基本クラスのデー
   タメンバやメンバ関数をそのまま使うときは何も
   書く必要はありません.
(2) 追加したいデータメンバや変更あるいは追加した
   いメンバ関数は P2.h のように明示します. 基本
   クラスに不要なものがあっても削除はできません.
(3) 派生クラスの定義は基本クラスには影響しません.

・簡単のため P1A.h でなく P1.h を用いました.
・group2 のコンストラクタの処理に追加する処理のみ
  を P2.h のように書きます.
・group2::show() の処理で group の show() を利用
  したいときは「group::」を付けて呼び出します.
・set_dan() は段級位設定のために追加した関数です.
・show() は group::show() を使っているので途中で
  改行されますが,これくらいは我慢しましょう.

細かい処理はともかく 基本クラスを利用すると派生ク
ラスのプログラミングが非常に楽になります.

             ***********

P2A.cpp: おまけ(無視してよい)
//-------------------------------------
#include "P2.h"
member igo[10]={{1, "A", "x"}, {2, "B", "y"}};
member2 igo2[10]={{1, 1}, {2, -1}};
member tennis[20]={{3, "C", "z"}};
int main(void){
  group *p1=new group(&tennis[0], 20), *p; 
  group2 *p2=new group2(&igo[0], 10, &igo2[0]); 
  member *q; char c;
  printf("club="); scanf("%c", &c);
  switch(c){
    case 'i': p=p2; q=&igo[0]; break;
    case 't': p=p1; q=&tennis[0]; break;
  }
  for(/* q=p->top_is() */; q->id!=0; q++){
    p->show(q->id);
  }
  return 0;
}
//-------------------------------------

多態性の説明です. P2A.cpp の p は group,group2 
のいずれのオブジェクトを指すかは実行時に決まりま
す.この結果,p->show() が group,group2 のいずれ
のものであるかもコンパイル時には分かりません(late 
binding).このプログラムを実行して,キー入力によっ
て表示形式が異なることを確認してください.

・group2 *p; のときは p=p1; とはできません.情報
  不足で処理できないことが起こりうるからです.
・P2h では top_is() がないので q を直接設定しまし
  たが q=p->top_is(); が望ましい.
・どうして実現するか興味のある人は,まず[0-2]の仮
  想関数テーブルの説明を見てください.

[2-1] 第9章 オーバーライド (含. 多態性)
[2-2] 第32章 privateやprotectedな継承