l VisualC クラス(一覧)_2 '97. 6.26
l.お知らせ 内容 LINK FILE   HTML Win PC Unix MS-DOS C C++ Mfc Java 
目次.C++言語_ 1 クラス 2 派生クラス 5 演算子のオーバーロード クラス(1)
 準備 3 オブジェクト 6 テンプレート 8 etc クラス(2)
 CC++ 4 フレンド・多重継承 7 メモリ確保・例外処理 未使用
演算子のオーバーロード   テンプレート化関数   テンプレート化クラス   メモリの確保と解放   new と delete のオーバーロード   例外処理   new の例外処理 

T 演算子のオーバーロード   (演算子の機能の変更)
演算子の元になっている関数を、新しく作り、新しく作った方を使います。

二項演算子=(定数の代入)
void
func (int i) { this->a=i; }
void
operator = (int i) { this->a=i; }
関数を普通に記述
演算子で呼出せるように記述
使うときは、メンバ a は忘れましょう。オブジェクトを変数と考えて利用します。
OB.func(5);
OB = 5;
普通の関数で呼び出し。 OB.a に、5 が代入されます。
演算子での呼び出し。 C1 型変数 OB に、5 が代入されます。

二項演算子=(変数の代入)
void
func (C1 ob) { this->a=ob.a; }
void
operator = (C1 ob) { this->a=ob.a; }
関数を普通に記述
演算子で呼出せるように記述
OB1.func(OB2);
OB1 = OB2;
普通の関数を呼び出し。 OB1.a に、OB2.a が代入されます。
演算子で呼び出し。 C1 型変数 OB1 に、OB2 が代入されます。

返り値が必要な演算子+のオーバーロード
void
func (C1 &ob) { return this->a+ob.a; }
void
operator + (C1 &ob) { return this->a+ob.a; }
関数を普通に記述
演算子で呼出せるように記述

単項演算子の 前置き と 後置き
 関数の宣言 関数の呼び出し
       int operator ++   ()       { /**/ }
       int operator ++   (int)    { /**/ }
friend int operator ++(C1 &ob)    { /**/ }
friend int operator ++(C1 &ob,int){ /**/ }
Y=++X; //(前置演算子)
Y=X++; //(後置演算子)
Y=++X; //(前置演算子)
Y=X++; //(後置演算子)
仮引数に int を追加しただけでは、演算の結果は変りません。 仮引数に int を記述して後置演算子にすると、関数の呼び出し方だけが変ります
T テンプレート化関数   (任意の型の引数を処理できる関数)
引数の型だけが異なる関数を、ひとつの関数として記述したものです。
グローバル関数として{クラス}の外に宣言します。

ひとつの型
void disp( int x ) { cout << x; } // 普通の関数
template <class t1>
void disp ( t1 x ) { cout << x; } // テンプレート化関数
 
同じ型
void disp( int x, int y ) { cout << x << y; }
template <class t1>
void disp ( t1 x , t1 y ) { cout << x << y; }
 
違う型
void disp( int x, char y) { cout << x << y; }
template <class t1, class t2 >
void disp ( t1 x , t2 y ) { cout << x << y; }
 
固定の型 (例えば char)
void disp( int x, char y ) { cout << x << y; }
template <class t1, char t2 >
void disp ( t1 x, char y ) { cout << x << y; }


T テンプレート化クラス   (オブジェクトの宣言時にメンバの型を決定できるクラス)

<テンプレートリスト>には、メンバのデータ型の組合せを指定します。
template<class t1, class t2, int x> なら、任意の型 t1 t2(二種類)を使用します。

(次の点はテンプレート化関数と違います。)
任意の型 t1 t2 は、オブジェクトを宣言するときに、<int, char, 5>のように具体的な型を指定します。
固定の型 int x は、関数の引数とは別にコンストラクタが受け取れます。
<テンプレートリスト>に書いた仮の型を、関数の(引数)に必ず使う必要はありません。

テンプレートクラスの宣言

class C1 { /**/}
template <class t1, class t2, int x>
class C1 { /**/}
普通のクラスの宣言
テンプレート化クラス


{クラス}の中にメンバ関数を宣言するとき

メンバ関数の定義
テンプレートリストで宣言した任意型が使用できる以外は、普通のクラスと同じです。
C1( t1 a ) { A=a; X=x; } // コンストラクタ
// パラメータリストの int x の値は、関数の引数とは別に受け取れます。
// パラメータリストの項目を全て使う必要はありません。

void func( t1b, int c ) { B=b; C=c; } // メンバ関数

メンバ関数をオーバーロードするときは
結果的に同じ引数の関数ができないようにします。
次のメンバ関数 func は、実質的に同じ引数になってしまいます。
template<class int> class C1 { /**/ };
C1< int > OB;
// このようなクラスで、
// このようにオブジェクトを宣言した場合、


void func( int a ) { /**/ } // 固定された引数型のメンバ関数
void func( t1 a ) { /**/ } // テンプレートリストの型を
// t1 は、オブジェクトの宣言時に int に決められていますから、ふたつの関数の引数は同じになってしまいます。
// なお後記のように、メンバ関数の定義をクラスの外に書く場合は、このような書式も許されます。

オブジェクトの宣言
オブジェクトの宣言で、そのオブジェクトのメンバのデータ型を指定します。
C1<int, char, 5> OB( 7 ); // クラス C1 のオブジェクト OB1 を宣言
// オブジェクト OB では、t1=int, t2=char, int x=5 にしました。

メンバ関数の呼び出し
特別な違いはありません。
普通のクラスの場合と同様に実引数を与えて呼び出します。



{クラス}の外にメンバ関数を宣言するとき

次の点が普通のクラスの場合と異なります。
1.テンプレート化クラスの宣言と同じテンプレートリストを書きます。
 これは、テンプレートリストを使わない関数では省略できます。
2.クラスの指定の後に、テンプレートリストの項目だけを書きます。
 これは、テンプレートリストを使わないメンバ関数でも省略できません。
3.メンバ関数がオーバーロードされているときは、
 テンプレートリストを使わない関数が優先的に呼び出されます。
template<class t1,class t2,int x>      C1<t1,t2,x>::C1( t1 a,int b){ A=a; B=b; }
template<class t1,class t2,int x> void C1<t1,t2,x>:: func1( t2 c ) { C=c;}
template<class t1,class t2,int x> void C1<int,int,5>::func1( t2 c ) { C=c+c; }
template<class t1,class t2>     void C1<int, char>::func2( int d ){ D=d;}
// t1,t2,x を <int,int,5> にして宣言したオブジェクトに対しては、
// func1() は、テンプレートリストを使わない二番目の func1() が働きます。
// この機能は、メンバ関数の定義をクラスの外に書く場合だけ、使用できるようです。

インライン関数の指定は
返り値の前(または後)に、inline と記述します。
上記の例では void の前(または後)に、inline と記述します。



T メモリの確保と解放

new と delete の用例
C1 *p;
p=new C1;
delete p;
// クラス用 C1 のポインタ変数を宣言
// クラス用 C1 のメモリを確保して、そのアドレスを p に代入
// 使い終わったらメモリを解放します

malloc と free の用例
#include <malloc.h>
int *p;
p=void *malloc(size_t n)
void free ( void *p )
// malloc() free()を使うために必要。stdlib.h でも可。
// int 型のポインタ変数 p を宣言
// n バイトを確保して、そのアドレスを p に代入
// p のメモリを解放します。


T new と delete のオーバーロード
演算子のオーバーロードの場合とほぼ同じです。

new の返り値は void * 型とします。
new を呼び出すときには、返り値が自動的に必要な型にキャストされます。
new の仮引数は size_t 型にします。
( size_t は unsigned int の別名です。malloc.h と stdlib.h に宣言されています。)
new を呼び出すときには、指定した実引数が自動的に size_t 型にキャストされます。
delete の仮引数は new と同じ型とします。
#include <stdlib.h> // malloc() free()を使うために必要
void *operator new (size_t n) { void *p=malloc(n); return p; }
void operator delete (void *p) { free(p); }


T 例外処理

すべてのエラーに対する例外処理
catch() は try{ } の直後に書きます。
try // エラー検出の、範囲の指定
{
// ここに普通にソースコードを書きます。
// ここでエラーが発生すると、catch() が呼び出されます。
}
catch( ... ) // 例外処理の内容
{ cout << "エラーが発生しました。\n"; }

特定の状態のときだけ例外処理を行いたい場合は、
try{ } の中に条件式を書いて catch() を呼び出します。
catch() を呼び出すには、catch() ではなく throw と書きます。
例   if( a<b ) thrrow 5; // 引数は( )で囲みません
この場合の catch() には、使わなくても引数を与える必要があります。
catch() は、引数を受け取る形に書き直します。
例   catch( int x ) { /**/ } 


T new の例外処理
new の例外処理は、_set_new_handler で登録できます。
1.例外処理を関数として記述します。
 この関数は、返り値を int 型にし、引数は size_t 型にします。
 返り値の値は0にします。
 0以外にすると、再びメモリの確保を繰返します。
 引数は、必要がなくても書きます。
2.その関数を、_set_new_handler で 例外処理 として登録します。

_set_new_handler は、その前に登録されていた例外処理のポインタを返すので、必要なら保存して、後で元に戻します。
_set_new_handler が返すポインタは特殊な _PNH 型なので、代入用のポインタ変数の宣言には _PNH 型を使います。

#include <new.h> // nwe の例外処理を行うために必要
int func(size_t n) // 例外処理用の関数を宣言
{ cout << "メモリ確保不可。\n"; return 0; }
// 必要なら、引数名 (n) を書きます。引数は確保しようとしたバイト数が受け取れます。
_PNH ph = _set_new_handler(func); // 例外処理関数を登録
C1 *OB=new C1 ; // C1 型のメモリを確保します。
delete ( OB ) ; // メモリを解放します。
_set_new_handler( ph ); // 例外処理の指定を元に戻します。

T

C++言語  クラス(1)  クラス(2)  MFC
 
  mtoga@sannet.ne.jp   登録日 '96. 6.15
URL : http://www.page.sannet.ne.jp/mtoga/index.html