Archive for 1月, 2010

C++でのクラスと構造体

前回C++のクラスは構造体の拡張であるという話し。
まず一般的な構造体から見ていきましょう、と。

#include <iostream>
#include <string.h>
using namespace std;
struct hoge
{
int a;
double b;
char c[128];
} foo;
int main()
{
hoge* pFoo = &foo;
foo.a = 100;
foo.b = 3.141592674;
strcpy(foo.c, "構造体のテストじゃ~。");
cout << "直接参照:\n" <<
"foo.a = " << foo.a <<
"\nfoo.b = " << foo.b <<
"\nfoo.c = " << foo.c << endl;
cout << "間接参照:\n" <<
"pFoo->a = " << pFoo->a <<
"\npFoo->b = " << pFoo->b <<
"\npFoo->c = " << pFoo->c << endl;
cout << "\n\n";
pFoo->a = 500;
pFoo->b = 1.05;
strcpy(pFoo->c, "ポインタから更新じゃじゃ~。");
cout << "直接参照:\n" <<
"foo.a = " << foo.a <<
"\nfoo.b = " << foo.b <<
"\nfoo.c = " << foo.c << endl;
cout << "間接参照:\n" <<
"pFoo->a = " << pFoo->a <<
"\npFoo->b = " << pFoo->b <<
"\npFoo->c = " << pFoo->c << endl;
return 0;
}

まぁ、これは普通に読めること前提。
一応実行結果はこれ。

直接参照:
foo.a = 100
foo.b = 3.14159
foo.c = 構造体のテストじゃ~。
間接参照:
pFoo->a = 100
pFoo->b = 3.14159
pFoo->c = 構造体のテストじゃ~。
直接参照:
foo.a = 500
foo.b = 1.05
foo.c = ポインタから更新じゃじゃ~。
間接参照:
pFoo->a = 500
pFoo->b = 1.05
pFoo->c = ポインタから更新じゃじゃ~。

で、これをそっくりクラスで書くと下記の通り。

#include <iostream>
#include <string.h>
using namespace std;
class hoge
{
public:
int a;
double b;
char c[128];
} foo;
int main()
{
hoge* pFoo = &foo;
foo.a = 100;
foo.b = 3.141592674;
strcpy(foo.c, "クラスのテストじゃ~。");
cout << "直接参照:\n" <<
"foo.a = " << foo.a <<
"\nfoo.b = " << foo.b <<
"\nfoo.c = " << foo.c << endl;
cout << "間接参照:\n" <<
"pFoo->a = " << pFoo->a <<
"\npFoo->b = " << pFoo->b <<
"\npFoo->c = " << pFoo->c << endl;
cout << "\n\n";
pFoo->a = 500;
pFoo->b = 1.05;
strcpy(pFoo->c, "ポインタから更新じゃじゃ~。");
cout << "直接参照:\n" <<
"foo.a = " << foo.a <<
"\nfoo.b = " << foo.b <<
"\nfoo.c = " << foo.c << endl;
cout << "間接参照:\n" <<
"pFoo->a = " << pFoo->a <<
"\npFoo->b = " << pFoo->b <<
"\npFoo->c = " << pFoo->c << endl;
return 0;
}

こんな風にpublic:をつけるだけ。
感がいい人はわかってると思うけど、構造体でもprivate:を付けてしまえばクラスっぽくなると言うね。
となると、構造体でもメンバ関数(メソッド)を用意することができる。

同じようなコードにすると下記なような感じになる。

#include <iostream>
#include <string.h>
using namespace std;
class CFoo
{
private:
int a;
double b;
char c[128];
public:
CFoo():a(0),b(0.0)
{
for (int i = 0; i < 128; ++i)
c[i] = '\0';
}
~CFoo() {}
int setA(int num)
{
a = num;
return 0;
}
int setB(double num)
{
b = num;
return 0;
}
int setC(char* szStr)
{
if (strlen(szStr) > 127) {
return 1;
}
strcpy(c, szStr);
return 0;
}
int getA() { return a; }
double getB() { return b; }
char* getC() { return c; }
};
struct Bar_t
{
private:
int a;
double b;
char c[128];
public:
Bar_t():a(0),b(0.0)
{
for (int i = 0; i < 128; ++i)
c[i] = '\0';
}
~Bar_t() {}
int setA(int num)
{
a = num;
return 0;
}
int setB(double num)
{
b = num;
return 0;
}
int setC(char* szStr)
{
if (strlen(szStr) > 127) {
return 1;
}
strcpy(c, szStr);
return 0;
}
int getA() { return a; }
double getB() { return b; }
char* getC() { return c; }
};
int main()
{
CFoo obj;
Bar_t obj2;
cout << "初期化時のクラス:\n" <<
"\tobj.getA() = " << obj.getA() <<
"\n\tobj.getB() = " << obj.getB() <<
"\n\tobj.getC() = " << obj.getC() << endl;
cout << "初期化時の構造体:\n" <<
"\tobj2.getA() = " << obj2.getA() <<
"\n\tobj2.getB() = " << obj2.getB() <<
"\n\tobj2.getC() = " << obj2.getC() << endl;
obj.setA(10000);
obj.setB(11.11);
obj.setC("我が輩の年齢は10万と26歳である、フハハハハ!");
obj2.setA(-1);
obj2.setB(42.195);
obj2.setC("オラ、ワクワクしてきたぞ!");
cout << "代入時のクラス:\n" <<
"\tobj.getA() = " << obj.getA() <<
"\n\tobj.getB() = " << obj.getB() <<
"\n\tobj.getC() = " << obj.getC() << endl;
cout << "代入時の構造体:\n" <<
"\tobj2.getA() = " << obj2.getA() <<
"\n\tobj2.getB() = " << obj2.getB() <<
"\n\tobj2.getC() = " << obj2.getC() << endl;
return 0;
}

何となく命名規則をそれっぽくしてみたけど、こんな感じ?
ほとんどというか、private:とpublic:を付けてしまえば両方とも一緒という結果。

そんだけ。

Post to Twitter

, , ,

No Comments

C++でのメンバ変数として、動的オブジェクトを作る

C++を勉強していて何が困ったって、メインで動的にメモリ領域をとる方法はたくさん載っているのに、クラスのメンバ変数を動的にとる方法がなかなか載っていない。
と言うわけで、いろいろ試行錯誤した結果、下記のようになった。

テスト用コード

#include <iostream>
#include <string.h>
using namespace std;
class hoge
{
public:
char* szStr;
hoge(char* szNewStr)
{
szStr = new char[strlen(szNewStr)];
strcpy(szStr, szNewStr);
}
~hoge() { delete szNewStr; }
};
int main()
{
char szStr[] = {"ばかやろ~~~~~~~~~~~~~~~"};
cout << szStr << endl;
cout << "end" << endl;
cout << strlen(szStr) << endl;
hoge* obj;
obj = new hoge(szStr);
cout << "\ntest\n";
cout << szStr << endl;
delete obj;
return 0;
}

実行結果。

ばかやろ~~~~~~~~~~~~~~~
end
57
test
ばかやろ~~~~~~~~~~~~~~~

まず、hogeなるクラスを定義します、と。
そのメンバ変数に動的に確保したい型のポインタを置きます、と。
それをコンストラクタなり、なんなりでnewしてあげるとそこにで動的に確保される、と。
ちなみに、ここで言う「型」というのは文字通りの型じゃなくても良くて、クラスでも良い。
なぜかというと、C++でのクラスは構造体を拡張したものだから。

その詳細はまた別の記事にて。

そんだけ。

Post to Twitter

, , ,

No Comments

C++でbad_alloc例外を2回取るテスト

と言うか、2回エラーをキャッチすることができるンかい?と言うお話し。
ほら、メモリを取得するときに多めにとってダメで、少なめに取ったらOKかもしれない場合、どうなのかなぁ?とかそんなこと思っただけ。
まぁ、メモリ取れなかった時点で普通はもうやめちゃう訳なんだけれども。
一応出来るのか出来ないのかをはっきりさせたかった。

で、テストコード。

#include <iostream>
#include <iomanip>
#include <new>
using namespace std;
#define MEMSIZE 10000000
int main()
{
double* pDat;
int i = MEMSIZE;
while (true) {
try {
pDat = new double[i];
}
catch (bad_alloc) {
pDat = NULL;
break;
}
cout << "#1 count " << setiosflags( ios::right )
<< setw(2) << i/MEMSIZE << "  |  "
<< setw(9) << i << "bytes | "
<< setw(6) << i/1000 << "Kbytes | "
<< setw(3) << i/1000000 << "Mbytes\n";
delete pDat;
i += MEMSIZE;
}
cout << "after bad_alloc\n";
i -= MEMSIZE;
cout << i/1000000 << "Mbytes can take " << i/sizeof(char) << " characters\n\n";
i = MEMSIZE;
while (true) {
try {
pDat = new double[i];
}
catch (bad_alloc) {
pDat = NULL;
break;
}
cout << "#2 count " << setiosflags( ios::right )
<< setw(2) << i/MEMSIZE << "  |  "
<< setw(9) << i << "bytes | "
<< setw(6) << i/1000 << "Kbytes | "
<< setw(3) << i/1000000 << "Mbytes\n";
delete pDat;
i += MEMSIZE;
}
cout << "after bad_alloc\n";
i -= MEMSIZE;
cout << i/1000000 << "Mbytes can take " << i/sizeof(char) << " characters\n\n";
return 0;
}

実行結果。

#1 count  1  |   10000000bytes |  10000Kbytes |  10Mbytes
#1 count  2  |   20000000bytes |  20000Kbytes |  20Mbytes
#1 count  3  |   30000000bytes |  30000Kbytes |  30Mbytes
#1 count  4  |   40000000bytes |  40000Kbytes |  40Mbytes
#1 count  5  |   50000000bytes |  50000Kbytes |  50Mbytes
#1 count  6  |   60000000bytes |  60000Kbytes |  60Mbytes
#1 count  7  |   70000000bytes |  70000Kbytes |  70Mbytes
#1 count  8  |   80000000bytes |  80000Kbytes |  80Mbytes
#1 count  9  |   90000000bytes |  90000Kbytes |  90Mbytes
#1 count 10  |  100000000bytes | 100000Kbytes | 100Mbytes
#1 count 11  |  110000000bytes | 110000Kbytes | 110Mbytes
#1 count 12  |  120000000bytes | 120000Kbytes | 120Mbytes
#1 count 13  |  130000000bytes | 130000Kbytes | 130Mbytes
#1 count 14  |  140000000bytes | 140000Kbytes | 140Mbytes
#1 count 15  |  150000000bytes | 150000Kbytes | 150Mbytes
after bad_alloc
#2 count  1  |   10000000bytes |  10000Kbytes |  10Mbytes
#2 count  2  |   20000000bytes |  20000Kbytes |  20Mbytes
#2 count  3  |   30000000bytes |  30000Kbytes |  30Mbytes
#2 count  4  |   40000000bytes |  40000Kbytes |  40Mbytes
#2 count  5  |   50000000bytes |  50000Kbytes |  50Mbytes
#2 count  6  |   60000000bytes |  60000Kbytes |  60Mbytes
#2 count  7  |   70000000bytes |  70000Kbytes |  70Mbytes
#2 count  8  |   80000000bytes |  80000Kbytes |  80Mbytes
#2 count  9  |   90000000bytes |  90000Kbytes |  90Mbytes
#2 count 10  |  100000000bytes | 100000Kbytes | 100Mbytes
#2 count 11  |  110000000bytes | 110000Kbytes | 110Mbytes
#2 count 12  |  120000000bytes | 120000Kbytes | 120Mbytes
#2 count 13  |  130000000bytes | 130000Kbytes | 130Mbytes
#2 count 14  |  140000000bytes | 140000Kbytes | 140Mbytes
#2 count 15  |  150000000bytes | 150000Kbytes | 150Mbytes
after bad_alloc

結論、出来るw

おそまつ。

Post to Twitter

, , ,

No Comments