Index |
 |
HOME >
プログラムTOP >
C++ |
|
C++の壺・クラス篇3
C++の基本テクニックのTipsです。 クラス篇3では、クラスの特殊な機能と、それらの使用方法を扱います。いずれも使用頻度は少ないと思いますが、プログラミングの効率化に大きな効果を発揮します。

クラスは、複数のクラスを継承することができます。継承先のクラス名に続いて、" , " で区切って継承元のクラス名を宣言します。この時、継承可能なメンバ(protected, public)は、すべて継承先のクラスで使用することができます。
// 多重継承
#include <stdio.h> // printf
#include <conio.h> // getch
// 継承元クラス1 : Pointクラス
class Point
{
public:
int left;
int top;
Point() {printf("start Point\n");}
~Point() {printf("end Point\n");}
};
// 継承元クラス2 : Sizeクラス
class Size
{
public:
int width;
int height;
Size() {printf("start Size\n");}
~Size() {printf("end Size\n");}
}; | // 継承先クラス : Regionクラス
class Region:public Point, public Size
{
public:
Region() {printf("start Region\n");}
~Region() {printf("end Region\n");}
};
// main 関数
void main()
{
Region* p;
p = new Region;
p->left = 60; // Pointのメンバ
p->top = 40; // Pointのメンバ
p->width = 480; // Sizeのメンバ
p->height = 360; // Sizeのメンバ
delete p;
if (getch()) return;
}
|
オブジェクトが作成される時、コンストラクタは継承元のものも呼ばれます。上記の例では、 Pointクラスのコンストラクタ → Sizeクラスのコンストラクタ → Regionクラスのコンストラクタ が順に呼び出されます。また、デストラクタも同様ですが、こちらは順番が逆です。上記の例では、 Regionクラスのデストラクタ → Sizeクラスのデストラクタ → Pointクラスのデストラクタ の順で呼ばれることになります。
通常、関数実行の際には、関数を呼び出す時間がかかります。インライン関数を使うと、このロスを防ぐことができます。ただし、この場合、関数は実行場所に直接埋め込まれるので、プログラムの量は実際の記述よりもかさんでしまいます。現実的には、一行か二行程度の関数に適用させることがほとんどです。 インライン関数を指定する場合は、関数の最初に inline を記述します。また、クラスの宣言時に同時に実装コードを記述すると、自動的にインライン関数として扱われます。なお、インライン関数は必ず実行されるわけではありません。
// メンバ関数のインライン化
#include <stdio.h> // printf
#include <stdlib.h> // rand
#include <time.h> // time
#include <conio.h> // getch
// 通常のメンバ関数の実装
class Random
{
public:
int GetNum(int len);
};
// GetNum関数
int Random::GetNum(int len) {
return rand() % len;
}
// インライン関数を明示して実装
class Random
{
public:
int GetNum(int len);
};
// GetNum関数
inline int Random::GetNum(int len) {
return rand() % len;
} |
// インライン関数として定義
class Random
{
public:
int GetNum(int len) {
return rand() % len;
}
}
// main 関数
void main()
{
Random* p = new Random;
clock_t t1 = clock(); // 時間1
int r;
int i = 0;
while (i < 10000000) {
r = p->GetNum(100);
i++;
}
clock_t t2 = clock(); // 時間2
printf("%d\n", t2-t1); // 経過時間
delete p;
if (getch()) return;
} |
上記は、関数を1000万回実行させた時のケースです。経過時間(tick数)は、筆者の環境では、通常では 966、インライン化した時は 922 (44tick分の向上)を示しました。よほどのパフォーマンスが要求される時以外は、あまり気にかける必要はないかもしれません。
クラス・テンプレートを使うと、ひとつのクラスで、複数のデータ型を扱えるようになります。下記のクラスは、単に足し算と引き算を行うだけのクラスです。左側が通常の定義と実装ですが、int 型を指定する必要があるため、他のデータ型を使用することができません。これを右側のようにテンプレート化すると、他のデータ型の代入が可能となります。 なお、クラス・テンプレートには既定のコンストラクタ / デストラクタがありません。new / delete を使用する可能性がある時は、コンストラクタとデストラクタを用意しておく必要があります。
// 通常のクラスの定義と実装
#include <stdio.h> // printf
#include <conio.h> // getch
// Calcクラス
class Calc
{
public:
int Plus(int a, int b);
int Minus(int a, int b);
};
int Calc::Plus(int a, int b) {
return a + b;
}
int Calc::Minus(int a, int b) {
return a - b;
}
// main 関数
void main() {
Calc *p = new Calc;
int n;
n = p->Plus(5, 2); // = 7
printf("%d\n", n);
n = p->Minus(5, 2); // = 3
printf("%d\n", n);
delete p;
if (getch()) return;
} |
// クラス・テンプレートの定義と実装
#include <stdio.h> // printf
#include <conio.h> // getch
// Calcクラス
template <typename _t> class Calc
{
public:
Calc();
~Calc();
_t Plus(_t a, _t b);
_t Minus(_t a, _t b);
};
// コンストラクタ
template <typename _t> Calc<_t>::Calc() {
}
// デストラクタ
template <typename _t> Calc<_t>::~Calc() {
}
// メンバ関数 Plus
template <typename _t>
_t Calc<_t>::Plus(_t a, _t b) {
return a + b;
}
// メンバ関数 Minus
template <typename _t>
_t Calc<_t>::Minus(_t a, _t b) {
return a - b;
} |
クラス・テンプレートを定義・実装する際は、上記のように、テンプレートであることを示すため、先頭に " template<一時的に使用するデータ型名> "を記述します。データ型名はプログラマの任意となります。また、クラス名の直後には、実際のデータ型を示す引数の記述も必要となります。 下記は、上記テンプレートを利用した例です。左側は整数型、右側は浮動小数点型を指定しています。
// クラス・テンプレートの使用1
// main 関数
void main()
{
// int型対応のCalcクラス
Calc<int>* p = new Calc<int>;
int n;
n = p->Plus(5, 2); // = 7
printf("%d\n", n);
n = p->Minus(5, 2); // = 3
printf("%d\n", n);
delete p;
if (getch()) return;
} | // クラス・テンプレートの使用2
// main 関数
void main()
{
// float型対応のCalcクラス
Calc<float>* p = new Calc<float>;
float f;
f = p->Plus(5.5, 2.2); // = 7.7
printf("%f\n", f);
f = p->Minus(5.5, 2.2); // = 3.3
printf("%f\n", f);
delete p;
if (getch()) return;
} |
|
www.sasaraan.net |
(c) morijoh |