アフィリエイト広告を利用しています

広告

posted by fanblog

2017年12月07日

《その167》 静的メンバへのポインタ & p.135演習3-14


 静的メンバへのポインタ

 静的データメンバへのポインタ や 静的メンバ関数へのポインタについて、チェックしてみたのが次のプログラムです。
 クラスの静的メンバを指すポインタは、通常のタイプのポインタ型として定義します。静的メンバは、クラスに属してはいますが、その実体は個々のクラスオブジェクトとは無関係なので、通常のタイプのポインタで指すことができます。

// ------------------------------------
#include <iostream>
using namespace std;

class C {
public:
static int n; // 静的データメンバ
static void func() { // 静的メンバ関数
std::cout << "static void func();\n";
}
int a; // 通常のデータメンバ
int get_a() const{ return a; }
// 通常のメンバ関数
C() { a = 1000; } // コンストラクタ
};

int C::n = 9999;
// 静的データメンバの実体は、クラス定義の外で
// static を付けずに定義する。


int main()
{
C test;

int *ptr1 = &C::n;
// 静的データメンバへのポインタ
void(*ptr2)() = &C::func;
// 静的メンバ関数へのポインタ
int C::*ptr3 = &C::a;
// 通常のデータメンバへのポインタ
int (C::*ptr4)() const= &C::get_a;
// 通常の静的メンバ関数へのポインタ

cout << *ptr1 << '\n';
(*ptr2)();
cout << test.*ptr3 << '\n';
cout << (test.*ptr4)() << '\n';
}
// ------------------------------------
f03_0039.png


新版明解C++中級編 p.135 演習3-14
 次のようなクラス Person と、Person型の配列がある。この配列をクイックソートアルゴリズムによってソートするプログラムを作成せよ。qsort関数を利用することなく実現すること。
【 クラス person 】
class Person {
public:
char name[10]; // 名前
int height; // 身長
int weight; // 体重
};

【 Person型の配列 】
Person x[]= {{"Shibata", 170, 52},
{"Takaoka", 180, 70},
{"Nangoh", 172, 63},
{"Sugiyama", 165, 50},
};

// p135_演習3-14
#include <iomanip>
#include <cstdlib>
#include <iostream>
using namespace std;

class Person {
public:
char name[10]; // 名前
int height; // 身長
int weight; // 体重
};

// x, yの指すnバイトの領域を交換する関数。
namespace {
void memswap(void* x, void* y, size_t n)
{
unsigned char* a = reinterpret_cast<unsigned char*>(x);
unsigned char* b = reinterpret_cast<unsigned char*>(y);

for (; n--; a++, b++) {
unsigned char c = *a;
*a = *b;
*b = c;
}
}
}

void quicksort(void* base, size_t nmemb, size_t size,
int(*compar)(const void*, const void*))
{
if (nmemb > 0) {
const char* v = reinterpret_cast<const char*>(base);
// 配列 base の先頭要素へのポインタ v
size_t pl = 0; // 探索範囲左端の位置(添字)
size_t pr = nmemb - 1; // 探索範囲右端の位置(添字)
size_t pv = nmemb; // 基準値の位置(添字)
size_t pt = (pl + pr) / 2; // 更新後の基準値の位置(添字)

do {
const char* x = &v[pt * size];
// const char*型のポインタ x
// 関数内の配列 v の各要素を指すポインタ用の変数です。
// v[pt * size] は 基準値 base[pt] に対応します。


if (pv != pt) x = &v[(pv = pt) * size];
// 基準値の位置に変更があった場合は、更新します。

while (compar(reinterpret_cast<const void*>(&v[pl * size]), x) < 0)
pl++;
// 探索範囲左端からチェックしていき、基準値のほうが大きければ、
// 探索範囲左端の位置 pl をインクリメント。
// 基準値以上の値を見つけたら、pl はその値の位置で止まります。


while (compar(reinterpret_cast<const void*>(&v[pr * size]), x) > 0)
pr--;
// 探索範囲右端からチェックしていき、基準値のほうが小さければ、
// 探索範囲右端の位置 pr をデクリメント。
// 基準値以下の値を見つけたら、pr はその値の位置で止まります。


if (pl <= pr) {
// 探索範囲の左端と右端が逆転していないうちは・・・
pt = (pl == pv) ? pr : (pr == pv) ? pl : pv;
// 探索範囲の左端が基準値の位置に達している場合は、基準値の位置
// を現時点での右端の位置に更新します。
// 探索範囲の右端が基準値の位置に達している場合は、基準値の位置
// を現時点での左端の位置に更新します。
// それ以外なら、基準値の位置は更新しません。
// ※以上の操作は、memswap関数が値を交換しても基準値の値が変化
// しないようにするため。


memswap(const_cast<void*>(reinterpret_cast<const void*>(&v[pl * size])),
const_cast<void*>(reinterpret_cast<const void*>(&v[pr * size])),
size);
pl++;
if (pr == 0) // 符号無し整数 0 からのデクリメントを避ける。
goto QuickRight;
pr--;
}
} while (pl <= pr);
// 配列 base は、do文が終了すると、quicksort関数内で最初に決めた
// 基準値 base[pt] に対してその値以上の部分と以下の部分に分けられます。


if (0 < pr)
// do文で二つに分けられた区間の左側を対象にして、
// quicksort関数を再帰的に呼び出します。

quicksort(const_cast<void*>(reinterpret_cast<const void*>(&v[0])),
pr + 1, size, compar);
QuickRight:
if (pl < nmemb - 1)
// do文で二つに分けられた区間の右側を対象にして、
// quicksort関数を再帰的に呼び出します。

quicksort(const_cast<void*>(reinterpret_cast<const void*>(&v[pl * size])),
nmemb - pl, size, compar);
}
}

int acmp(char* x, char* y) {
// 比較関数 : 配列による文字列用
return strcmp(x, y);
}

int pcmp(char** x, char** y) {
// 比較関数 : ポインタによる文字列用
return strcmp(*x, *y);
}

int ncmp(int* x, int* y) {
// 比較関数 : int型の整数用
return *x < *y ? -1 :
*x > *y ? 1 : 0;
}

int npcmp(const Person* x, const Person* y) {
// 比較関数 : Person型の名前メンバ用
return strcmp((*x).name, (*y).name);
}

int hpcmp(const Person* x, const Person* y) {
// 比較関数 : Person型の身長メンバ用
return (*x).height < (*y).height ? -1 :
(*x).height >(*y).height ? 1 : 0;
}

int wpcmp(const Person* x, const Person* y) {
// 比較関数 : Person型の体重メンバ用
return (*x).weight < (*y).weight ? 1 :
(*x).weight >(*y).weight ? -1 : 0;
}

void print_person(const Person x[], int no) {
// Person型データを一覧表示
for (int i = 0; i < no; i++)
cout << setw(10) << left << x[i].name << " "
<< x[i].height << "cm " << x[i].weight << "kg\n";
}


int main()
{
Person x[] = { { "Shibata", 170, 52 },
{ "Takaoka", 180, 70 },
{ "Nangoh", 172, 63 },
{ "Sugiyama", 165, 50 },
};

int nx = sizeof(x) / sizeof(x[0]);

puts("ソート前");
print_person(x, nx);

// 名前昇順にソート
quicksort(x, nx, sizeof(Person),
reinterpret_cast<int(*)(const void*, const void*)>(npcmp));

cout << "\n名前昇順ソート後\n";
print_person(x, nx);

// 身長昇順にソート
quicksort(x, nx, sizeof(Person),
reinterpret_cast<int(*)(const void*, const void*)>(hpcmp));

cout << "\n身長昇順ソート後\n";
print_person(x, nx);

// 体重降順にソート
quicksort(x, nx, sizeof(Person),
reinterpret_cast<int(*)(const void*, const void*)>(wpcmp));

cout << "\n体重降順ソート後\n";
print_person(x, nx);
}

f03_14.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/11/10 13:13時点)

新版 明解C 中級編 (明解シリーズ)

新品価格
¥2,916から
(2017/11/10 13:14時点)





この記事へのコメント
コメントを書く

お名前:

メールアドレス:


ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバックURL
https://fanblogs.jp/tb/7064376
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


検索
<< 2018年08月 >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
プロフィール
こうすけさんの画像
こうすけ

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


×

この広告は30日以上新しい記事の更新がないブログに表示されております。