突然ですが、引数つきマクロはインライン関数のように定義内容をコード上に展開する
機能を持っています。そのため、引数つきマクロを使うと、インライン関数と同じことが
できます。しかし、できるだけインライン関数を使ったほうがよいということがあります。
引数つきマクロを使って、2つの数から大きいほうの数値を求めるマクロを例に
見て行きましょう。^^
//3項演算子を使っていると、とってもできる人みたいに見える気がします。
#define MAXNUM(a, b) ( (a) > (b) ? (a) : (b) )
ちなみに同じ処理をインライン関数にすると、次のようになります。
inline int MaxNumFunc(int a, int b)
{
if (a > b) return a;
return b;
}
引数つきマクロはわずか1行ですが、インライン関数は空行も含めると6行にも
なってしまいました。
一見すると引数つきマクロのほうが便利そうなのですが、実は副作用がでる
ケースも存在します。
例えば次のように実行すると、引数つきマクロではインクリメントが2回行われて
しまうのです。
b1++が2ヶ所に展開されるので、b1が2回インクリメントされてしまいます。(^_^;)
:
int a1 = 11, b1 = 13;
//呼び出しで1回、マクロ内の判定で1回で合計2回b1がインクリメントされます。
int n1 = MAXNUM(a1++, b1++);
cout << "a1 = " << a1 << " b1 = " << b1 << endl;
cout << "n1 = " << n1 << endl;
int a2 = 12, b2 = 14;
//インライン関数では、インクリメントが1回です。
int n1 = MaxNumFunc(a2++, b2++);
cout << "a2 = " << a2 << " b2 = " << b2 << endl;
cout << "n2 = " << n2 << endl;
:
実行結果
# ./test
a1 = 12 b1 = 15
n1 = 14
a2 = 13 b2 = 15
n2 = 14
どうやら違う結果になりえるというのが理解いただけたかと。(^_^;)
また、モノによって使えるマクロ、使えないマクロを判断するのは面倒ですから
それだったらはじめからインライン関数で作っておけば、今回のようなケースでも
対応可能となり問題は発生しません。
ひょっとしたらバグっているけども気づかれないパターンで救われているのかしら?
マクロになっているところは一度見直してみるのもいいかもしれませんね。
約束の時間計測でインライン関数の高速ぶりを検証
前回はインライン関数の高速ぶりが全く伝わらなかったのでリベンジしようかと。
ということで、sqrt(x * x + y * y) の計算を普通の関数およびインライン関数で
1000000 回計算するというサンプルを見つけたのでコレを試してみます。(^^)
http://www.sist.ac.jp/~suganuma/learn/2-bu/7-sho/7-5/7-5.htm
実行結果のみ載せています。
# ./functiontest
answer is 11
time = 0.522189
# ./inlinetest
answer is 11
time = 0.505161
これは、インライン関数のほうが0.017028秒早いですね。
サンプルでは微々たる差分ですが、この積み重ねでユーザーがイライラしない
システムというのが出来上がります。
プロになることを見据えて、実行時間にも拘りたいものですね。(^^)
今日の名言
あの太陽の輝く遥か彼方に、私の最も憧れている何物かがあります。たとえ、そこに
達することができなくても、私は頭を上げてその美しさを眺め、そこにあることを信じ、
その指差す方向へついていくことが出来るのです。
ルイーザ・メイ・オルコット
心を打ち込んで事に当たれば、右手を二本得たも同然である。
エルバート・ハバード
熱中ほど伝染しやすいものはない。これこそ真のオルフェウス神話である。熱中は
岩をも動かし野獣をもうっとりさせる。それは誠意の守護神であり、これなくして
勝利はありえない。
エドワード・ブルワー・リットン
2013年8月31日土曜日
2013年8月29日木曜日
インライン関数とは
インライン関数とは、その名の通り実行時にソースコードの関数呼び出し口に
展開される関数のことです。インライン関数のメリットは関数呼び出しにかかる
時間を節約できることです。
関数に inline をつけることで、コンパイル時に呼び出し箇所への関数定義が
できるだけ展開されるようになります。これがインライン関数です。
注意する点は、コンパイラは必ずインライン関数を呼び出し箇所に展開するわけでは
ないということです。(^_^;)
インライン関数例
inline int CalcAddNumber(int x, inb y)
{
return x + y;
}
:
int main(void)
{
CalcAddNumber(5, 10); //ここで上記のインライン関数が展開されます
:
:
インライン関数にすると、引数をコピーするなどの関数呼び出し時の処理が省略され
実行時間が早くなります。しかしその一方、プログラムのサイズが大きくなってしまうので
何でもかんでもインライン関数にすればよいというわけではありません。(ーー;)
では、ここでサンプルプログラムでちょっと時間計測をしてみましょうか
#include <iostream>
#include <stdio.h>
#include <sys/time.h>
using namespace std;
//CalcAddNumberのこの2行をコメントにするほうを切り替えて
//比較してみたいと思います
inline int CalcAddNumber(int x, int y)
//int CalcAddNumber(int x, int y)
{
return x + y;
}
int main(void)
{
struct timeval start, end;
gettimeofday(&start, NULL);
int ans = CalcAddNumber(5, 10);
gettimeofday(&end, NULL);
cout << "answer is " << ans << endl;
cout << "time = " << (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)*1e-6 << endl;
printf("time = %f\n", (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)*1e-6);
return 0;
}
インライン関数(inline int CalcAddNumber(int x, int y))の結果
# ./test
answer is 15
time = 4e-06
time = 0.000004
通常の関数(int CalcAddNumber(int x, int y))の結果
# ./test
answer is 15
time = 4e-06
time = 0.000004
うーん、見事に同じですね(^_^;)
処理が少し簡単すぎたようで、これでは比較できてないですね、残念。
次回もっといいネタを探して書くことにします(汗)
インライン関数を定義する場所
インライン関数の定義内容は、どのファイルからでも参照できるように
ヘッダファイル(*.h)に記載します。
インライン関数にすると良い関数
処理内容の少ない関数は、呼び出し箇所へ展開されてもプログラムサイズに
ほとんど影響しません。また、小さい関数の場合は、関数全体の処理に対して
呼び出し処理にかかる時間の割合のほうが大きくなるので効果的です。
小さい関数の場合は、インライン関数にするとかなり効果が期待できます^^
また、呼び出し回数の多い関数をインライン関数にするのも効果的です。
何度もループで呼び出されるような小さい関数をインライン関数にすることで、
実行時間の節約にもなります。
インライン関数をうまく使って、速いプログラムが作れるようになりたいものです(^^)
今日の名言
どんな職業につこうと、成功に向かう第一歩は、その職業に興味を持つことだ。
サー・ウィリアム・オスラー
強い信念によって強い人間が生まれる。そしていっそう人間を強くする。
ウォルター・バジョット
限りなく心を打ち込んでかかれる事柄であれば、人間は大抵のものに成功できる。
チャールズ・シュワップ
人間が臨終に際して、子孫に熱中する心を伝えることができれば、
無限の価値ある財産を残したことになる。
トーマス・A・エジゾン
何か1つ趣味を持たない限り、人間は真の幸福も安心も得られない。植物学、蝶や
カブトムシの採集、バラやチューリップ、スイセンの花作り、釣り、登山、骨董-その他
どんなものに興味を持とうと、その人の人生は素晴らしいものに変化する。趣味という
馬を乗りこなせる限り、何の趣味でもかまわない。
サー・ウィリアム・オスラー
展開される関数のことです。インライン関数のメリットは関数呼び出しにかかる
時間を節約できることです。
関数に inline をつけることで、コンパイル時に呼び出し箇所への関数定義が
できるだけ展開されるようになります。これがインライン関数です。
注意する点は、コンパイラは必ずインライン関数を呼び出し箇所に展開するわけでは
ないということです。(^_^;)
インライン関数例
inline int CalcAddNumber(int x, inb y)
{
return x + y;
}
:
int main(void)
{
CalcAddNumber(5, 10); //ここで上記のインライン関数が展開されます
:
:
インライン関数にすると、引数をコピーするなどの関数呼び出し時の処理が省略され
実行時間が早くなります。しかしその一方、プログラムのサイズが大きくなってしまうので
何でもかんでもインライン関数にすればよいというわけではありません。(ーー;)
では、ここでサンプルプログラムでちょっと時間計測をしてみましょうか
#include <iostream>
#include <stdio.h>
#include <sys/time.h>
using namespace std;
//CalcAddNumberのこの2行をコメントにするほうを切り替えて
//比較してみたいと思います
inline int CalcAddNumber(int x, int y)
//int CalcAddNumber(int x, int y)
{
return x + y;
}
int main(void)
{
struct timeval start, end;
gettimeofday(&start, NULL);
int ans = CalcAddNumber(5, 10);
gettimeofday(&end, NULL);
cout << "answer is " << ans << endl;
cout << "time = " << (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)*1e-6 << endl;
printf("time = %f\n", (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)*1e-6);
return 0;
}
インライン関数(inline int CalcAddNumber(int x, int y))の結果
# ./test
answer is 15
time = 4e-06
time = 0.000004
通常の関数(int CalcAddNumber(int x, int y))の結果
# ./test
answer is 15
time = 4e-06
time = 0.000004
うーん、見事に同じですね(^_^;)
処理が少し簡単すぎたようで、これでは比較できてないですね、残念。
次回もっといいネタを探して書くことにします(汗)
インライン関数を定義する場所
インライン関数の定義内容は、どのファイルからでも参照できるように
ヘッダファイル(*.h)に記載します。
インライン関数にすると良い関数
処理内容の少ない関数は、呼び出し箇所へ展開されてもプログラムサイズに
ほとんど影響しません。また、小さい関数の場合は、関数全体の処理に対して
呼び出し処理にかかる時間の割合のほうが大きくなるので効果的です。
小さい関数の場合は、インライン関数にするとかなり効果が期待できます^^
また、呼び出し回数の多い関数をインライン関数にするのも効果的です。
何度もループで呼び出されるような小さい関数をインライン関数にすることで、
実行時間の節約にもなります。
インライン関数をうまく使って、速いプログラムが作れるようになりたいものです(^^)
今日の名言
どんな職業につこうと、成功に向かう第一歩は、その職業に興味を持つことだ。
サー・ウィリアム・オスラー
強い信念によって強い人間が生まれる。そしていっそう人間を強くする。
ウォルター・バジョット
限りなく心を打ち込んでかかれる事柄であれば、人間は大抵のものに成功できる。
チャールズ・シュワップ
人間が臨終に際して、子孫に熱中する心を伝えることができれば、
無限の価値ある財産を残したことになる。
トーマス・A・エジゾン
何か1つ趣味を持たない限り、人間は真の幸福も安心も得られない。植物学、蝶や
カブトムシの採集、バラやチューリップ、スイセンの花作り、釣り、登山、骨董-その他
どんなものに興味を持とうと、その人の人生は素晴らしいものに変化する。趣味という
馬を乗りこなせる限り、何の趣味でもかまわない。
サー・ウィリアム・オスラー
2013年8月24日土曜日
C++ スコープ解決演算子とは?
スコープとは変数や関数の有効範囲のことを指しています。
もし、この有効範囲内に同名の変数や関数がある場合は、スコープ解決演算子を
使います。^^
ローカル変数とグローバル変数の名前が同じとき、関数内ではローカル変数が
優先されます。これはなんとなくイメージできるのではないでしょうか?
しかし、スコープ解決演算子を使うことで、グローバル変数を優先させることが
できるようになります。
例えばこんな風に使われます。
//:: がスコープ解決演算子です。
::myname; //グローバル変数の myname にアクセスします
そして、スコープ解決演算子の前にクラス名をつけると、オブジェクト内のメンバ変数を
使うということが明示できます。
//Personクラスのオブジェクトにあるメンバ変数のmynameにアクセスします。^^
Person::myname;
スコープ解決演算子を使ったサンプルプログラム
#include <iostream>
#include <string.h>
using namespace std;
char myname[] = "グローバル時代を席巻するジェイムズ";
class Person{
public:
Person();
private:
char myname[64];
};
Person::Person()
{
char myname[] = "ローカルエリアネットワークにいるジェイムズ";
strncpy(Person::myname, "パーソンクラスにいるジェイムズ",
sizeof("パーソンクラスにいるジェイムズ"));
//ローカル変数
cout << "My name is " << myname << endl;
//メンバ変数
cout << "My name is " << Person::myname << endl;
//グローバル変数
cout << "My name is " << ::myname << endl;
}
int main(void)
{
Person myPerson;
return 0;
}
実行結果
# ./test
My name is ローカルエリアネットワークにいるジェイムズ
My name is パーソンクラスにいるジェイムズ
My name is グローバル時代を席巻するジェイムズ
何故ジェイムズだったのかというと、今日の名言に登場するからです(^_^;)
また、スコープ解決演算子は、関数やオブジェクトへアクセスする時にも
同じように使います。
とても便利ですね、スコープ解決演算子(^^)
例
//グローバル関数(メンバ関数以外)のGetPersonAge()関数にアクセスします。
::GetPersonAge();
今日の名言
年をとれば額にしわがよるのは仕方がないが、心にまでしわを作ってはならない。
ジェイムズ・A・ガーフィールド
人生において重要なことは、大きな目標を持つとともに、それを達成できる
能力と体力を持つことである。
ヨハン・ウォルフガング・フォン・ゲーテ
自分のことで卑屈になったり、引っ込み思案になったりしがちなのを克服する
最上の方法は、他人に興味を持ち、他人のことを考えることだ。気後れなど
うその様に消え去ってしまう。他人のために何か尽くしてやることだ。常に人に
親切を尽くし、友人のような心で接すれば、あなたはそのすばらしい結果に
驚くことだろう。
デール・カーネギー
熱中する心がなければ、この世に進歩はありえない。
ウッドロー・ウィルソン
もし、この有効範囲内に同名の変数や関数がある場合は、スコープ解決演算子を
使います。^^
ローカル変数とグローバル変数の名前が同じとき、関数内ではローカル変数が
優先されます。これはなんとなくイメージできるのではないでしょうか?
しかし、スコープ解決演算子を使うことで、グローバル変数を優先させることが
できるようになります。
例えばこんな風に使われます。
//:: がスコープ解決演算子です。
::myname; //グローバル変数の myname にアクセスします
そして、スコープ解決演算子の前にクラス名をつけると、オブジェクト内のメンバ変数を
使うということが明示できます。
//Personクラスのオブジェクトにあるメンバ変数のmynameにアクセスします。^^
Person::myname;
スコープ解決演算子を使ったサンプルプログラム
#include <iostream>
#include <string.h>
using namespace std;
char myname[] = "グローバル時代を席巻するジェイムズ";
class Person{
public:
Person();
private:
char myname[64];
};
Person::Person()
{
char myname[] = "ローカルエリアネットワークにいるジェイムズ";
strncpy(Person::myname, "パーソンクラスにいるジェイムズ",
sizeof("パーソンクラスにいるジェイムズ"));
//ローカル変数
cout << "My name is " << myname << endl;
//メンバ変数
cout << "My name is " << Person::myname << endl;
//グローバル変数
cout << "My name is " << ::myname << endl;
}
int main(void)
{
Person myPerson;
return 0;
}
実行結果
# ./test
My name is ローカルエリアネットワークにいるジェイムズ
My name is パーソンクラスにいるジェイムズ
My name is グローバル時代を席巻するジェイムズ
何故ジェイムズだったのかというと、今日の名言に登場するからです(^_^;)
また、スコープ解決演算子は、関数やオブジェクトへアクセスする時にも
同じように使います。
とても便利ですね、スコープ解決演算子(^^)
例
//グローバル関数(メンバ関数以外)のGetPersonAge()関数にアクセスします。
::GetPersonAge();
今日の名言
年をとれば額にしわがよるのは仕方がないが、心にまでしわを作ってはならない。
ジェイムズ・A・ガーフィールド
人生において重要なことは、大きな目標を持つとともに、それを達成できる
能力と体力を持つことである。
ヨハン・ウォルフガング・フォン・ゲーテ
自分のことで卑屈になったり、引っ込み思案になったりしがちなのを克服する
最上の方法は、他人に興味を持ち、他人のことを考えることだ。気後れなど
うその様に消え去ってしまう。他人のために何か尽くしてやることだ。常に人に
親切を尽くし、友人のような心で接すれば、あなたはそのすばらしい結果に
驚くことだろう。
デール・カーネギー
熱中する心がなければ、この世に進歩はありえない。
ウッドロー・ウィルソン
2013年8月22日木曜日
標準入力ストリームとは?
これまでは、データを出力する話でしたが、今回からデータ入力もできるようになります^^
std::cin
C++では、キーボードから入力したデータを受け取る場合に 標準入力ストリームである
std::cin を使うことができます。デフォルトの標準入力はキーボードとなっています。
cin は istreamクラスのオブジェクトです。
次の例を見てください。
//std::cin を使うためには、iostream をインクルードしてください
#include <iostream>
using namespace std; //std::cin を cin に、std::cout, std::endlのstd::を書かないため
int main(void)
{
int num = 0;
cout << "Please input favorite number." << endl;
cin >> num;
cout << "Input number is " << num << endl;
return 0;
}
実行結果 赤字の4がキー入力です
# ./test
Please input favorite number.
4
Input number is 4
つづいて、文字列の入力を試してみます^^
#include <iostream>
using namespace std; //どうしてもstd::を書きたくない
int main(void)
{
char name[50];
cout << "Please input your name." << endl;
cin >> name; //入力された文字列を変数nameに格納します
cout << "Hello, " << name << ". How are you?" << endl;
return 0;
}
実行結果 赤字がキー入力です
# ./test2
Please input your name.
K.Yamagata
Hello, K.Yamagata. How are you?
cinを使うとscanf()関数と同様に1文字がスペースやタブで区切られて格納されます。
そのため以下のような入力をした場合、スペースのあとの文字は格納されません。
# ./test2
Please input your name.
K Yamagata //K と Yamagataの間にスペースを入れてEnter
Hello, K. How are you? //Kだけ表示された
もしスペース以下も格納したい場合は次のようにしてください。^^
//std::cinのメンバ関数 getline を使っています
cin.getline(name, sizeof(name));
標準入出力を使用するメリット
coutやcinでは、printf()やscanf()関数と比べると、書式と変数の対応を意識しなくて
よいので便利です。またcinでは変数に&をつけるのかなどと悩む必要もありません。
cout, cin せっかくなので、どんどん使っていきたいと思います(^^)
今日の名言
長生きすればするほど、物事に没頭できる人は、人間として一番大切な資格または天性を
備えている、と確信するようになった。成功者と失敗者の実力は、技量の点でも才能の点
でも、大差はないようだ。しかし知能も技能も体力もすべて等しい二人の人間が、同時に
スタートを切ったとすれば、没頭できる人間のほうが先に到達する。また、たとえ実力は
二流であっても、物事に没頭できるタイプであれば、没頭できないタイプの一流の人間に
勝つことが、しばしばある。
フレデリック・ウィリアムソン
愛してその人を得ることは最上である。愛してその人を失うことは、その次によい。
ウィリアム・メイクピース・サッカレー
不可能だと思わない限り、人間は決して敗北しない。
デール・カーネギー
std::cin
C++では、キーボードから入力したデータを受け取る場合に 標準入力ストリームである
std::cin を使うことができます。デフォルトの標準入力はキーボードとなっています。
cin は istreamクラスのオブジェクトです。
次の例を見てください。
//std::cin を使うためには、iostream をインクルードしてください
#include <iostream>
using namespace std; //std::cin を cin に、std::cout, std::endlのstd::を書かないため
int main(void)
{
int num = 0;
cout << "Please input favorite number." << endl;
cin >> num;
cout << "Input number is " << num << endl;
return 0;
}
実行結果 赤字の4がキー入力です
# ./test
Please input favorite number.
4
Input number is 4
つづいて、文字列の入力を試してみます^^
#include <iostream>
using namespace std; //どうしてもstd::を書きたくない
int main(void)
{
char name[50];
cout << "Please input your name." << endl;
cin >> name; //入力された文字列を変数nameに格納します
cout << "Hello, " << name << ". How are you?" << endl;
return 0;
}
実行結果 赤字がキー入力です
# ./test2
Please input your name.
K.Yamagata
Hello, K.Yamagata. How are you?
cinを使うとscanf()関数と同様に1文字がスペースやタブで区切られて格納されます。
そのため以下のような入力をした場合、スペースのあとの文字は格納されません。
# ./test2
Please input your name.
K Yamagata //K と Yamagataの間にスペースを入れてEnter
Hello, K. How are you? //Kだけ表示された
もしスペース以下も格納したい場合は次のようにしてください。^^
//std::cinのメンバ関数 getline を使っています
cin.getline(name, sizeof(name));
標準入出力を使用するメリット
coutやcinでは、printf()やscanf()関数と比べると、書式と変数の対応を意識しなくて
よいので便利です。またcinでは変数に&をつけるのかなどと悩む必要もありません。
cout, cin せっかくなので、どんどん使っていきたいと思います(^^)
今日の名言
長生きすればするほど、物事に没頭できる人は、人間として一番大切な資格または天性を
備えている、と確信するようになった。成功者と失敗者の実力は、技量の点でも才能の点
でも、大差はないようだ。しかし知能も技能も体力もすべて等しい二人の人間が、同時に
スタートを切ったとすれば、没頭できる人間のほうが先に到達する。また、たとえ実力は
二流であっても、物事に没頭できるタイプであれば、没頭できないタイプの一流の人間に
勝つことが、しばしばある。
フレデリック・ウィリアムソン
愛してその人を得ることは最上である。愛してその人を失うことは、その次によい。
ウィリアム・メイクピース・サッカレー
不可能だと思わない限り、人間は決して敗北しない。
デール・カーネギー
2013年8月18日日曜日
標準出力ストリームとは
今回は標準出力ストリームでのデータ出力についての記事です。^^
ずいぶん前に、 std::cout について書いたと思うのですが、これは標準出力ストリームと
いって、いろいろな型の変数や値を標準出力するのに使います。
標準出力先はどこかというと、デフォルトではプログラム実行画面(ディスプレイ)です。
std::cout はこれまでにも何度も使っています。iostream ヘッダをインクルードします。
そして、何度もstd:: を書きたくないために、すぐあとに using namesapce std; を
書いていました。
#include <iostream>
using namespace std;
int main(void)
{
cout << "Hello, Work!" << endl;
return 0;
}
ここで、 「<<」についてですが、これは出力ストリーム演算子といいます。
この右に記述した変数や値が出力対象となります。
「<<」 を複数使用すると、変数や値が同時にいくつも出力することができます。
#include <iostream>
using namespace std;
int main(void)
{
int num = 1;
cout << "Hello, Work!" << endl;
cout << "This is Test program No." << num << endl;
return 0;
}
実行結果
# ./test
Hello, Work!
This is Test program No.1
#
どうでしょうか、printf()関数より簡単ではないでしょうか?
C++ではcout, printf どちらも使うことができますので、必要に応じ使い分けても
いいでしょう。特にデバッグ時はprintf()を使うことが多いかもしれません。(^_^;)
また、std::endl にはバッファからすぐに出力する、改行するという役割があります。
これによって上記プログラムでは、画面に文字列を出力したあとに改行されプロンプトが
すぐ下に来ているのです。(赤#のところです)
出力指定子で書式を指定してみる
次は、以前に少し試した出力指定子での書式の指定方法についてです。
std::cout は、ostreamというクラスのオブジェクトです。このクラスでは、書式指定のための
さまざまなメンバ関数が用意されています。
空白を含めた4文字で表示 0を使って4文字で表示
cout.width(4); cout.fill('0');
cout << 10; cout.width(4);
cout << 10;
↓ ↓
__10(見えないので__で表記してます) 0010
また、実数を表示する場合は、小数点の前後の桁数を指定します。^^
全体を6文字で、数値の桁数は4桁まで
cout.width(6);
cout.precision(4); //precision = 精度という意味です
cout << 123.45;
↓
_123.45
小数点を含め全体で6文字なので5は表示されません。
そして、空白や小数点を除く整数部分と、小数点以下の数値を合わせて
4桁になっているのがわかりますね^^
文字列の表示形式も同様です。
char string[] = "orange";
cout.width(8); //全体で8文字にしてみます
cout << string << endl;
↓
__orange
先頭に空白が入って、右寄せになります。^^
width(), fill(), precision()の指定は出力のたびに行わなければなりません。
(コンパイラによって異なります)
個人的には、あるスコープまでという様に指定できたら便利なのに...
と思ったりもしています(^_^;)
今日の名言
私は新内閣に加わった方々に述べた言葉を、今ここで議会に向かって繰り返したい。
「私の捧げ得るものは、血、労力、涙と汗だけである。」我々は未曾有の大試練に直面して
いる。 我々の前には、長い苦悩と苦闘に年月が横たわっている。
我々の政策は何か、と問われたら、私はこう答えるだろう。「それは、神が与えたまう限りの
あらゆる力を動員して、海上に、陸上に、空中に、戦って戦い抜くことである。人類の罪悪
史上いまだかつて例をみない大暴君を相手に戦い抜くことである。」これが我が国の
政策である。
我が内閣の目的は何か、と問われたら、私はただ一言「勝利!」と答えよう。あらゆる
犠牲を払って勝利を得るのだ。どんな恐ろしい目にあおうと勝利を得るのだ。あらゆる困難を
克服して勝利を得るのだ。勝利なくして、我々の生存はありえないからだ。
ウィンストン・チーチャル
恐怖心は、暴れん坊だが同時に臆病者である。恐怖心を克服するには、
その存在を無視すればよい。あなたにはできるはずだ。
デール・カーネギー
ずいぶん前に、 std::cout について書いたと思うのですが、これは標準出力ストリームと
いって、いろいろな型の変数や値を標準出力するのに使います。
標準出力先はどこかというと、デフォルトではプログラム実行画面(ディスプレイ)です。
std::cout はこれまでにも何度も使っています。iostream ヘッダをインクルードします。
そして、何度もstd:: を書きたくないために、すぐあとに using namesapce std; を
書いていました。
#include <iostream>
using namespace std;
int main(void)
{
cout << "Hello, Work!" << endl;
return 0;
}
ここで、 「<<」についてですが、これは出力ストリーム演算子といいます。
この右に記述した変数や値が出力対象となります。
「<<」 を複数使用すると、変数や値が同時にいくつも出力することができます。
#include <iostream>
using namespace std;
int main(void)
{
int num = 1;
cout << "Hello, Work!" << endl;
cout << "This is Test program No." << num << endl;
return 0;
}
実行結果
# ./test
Hello, Work!
This is Test program No.1
#
どうでしょうか、printf()関数より簡単ではないでしょうか?
C++ではcout, printf どちらも使うことができますので、必要に応じ使い分けても
いいでしょう。特にデバッグ時はprintf()を使うことが多いかもしれません。(^_^;)
また、std::endl にはバッファからすぐに出力する、改行するという役割があります。
これによって上記プログラムでは、画面に文字列を出力したあとに改行されプロンプトが
すぐ下に来ているのです。(赤#のところです)
出力指定子で書式を指定してみる
次は、以前に少し試した出力指定子での書式の指定方法についてです。
std::cout は、ostreamというクラスのオブジェクトです。このクラスでは、書式指定のための
さまざまなメンバ関数が用意されています。
空白を含めた4文字で表示 0を使って4文字で表示
cout.width(4); cout.fill('0');
cout << 10; cout.width(4);
cout << 10;
↓ ↓
__10(見えないので__で表記してます) 0010
また、実数を表示する場合は、小数点の前後の桁数を指定します。^^
全体を6文字で、数値の桁数は4桁まで
cout.width(6);
cout.precision(4); //precision = 精度という意味です
cout << 123.45;
↓
_123.45
小数点を含め全体で6文字なので5は表示されません。
そして、空白や小数点を除く整数部分と、小数点以下の数値を合わせて
4桁になっているのがわかりますね^^
文字列の表示形式も同様です。
char string[] = "orange";
cout.width(8); //全体で8文字にしてみます
cout << string << endl;
↓
__orange
先頭に空白が入って、右寄せになります。^^
width(), fill(), precision()の指定は出力のたびに行わなければなりません。
(コンパイラによって異なります)
個人的には、あるスコープまでという様に指定できたら便利なのに...
と思ったりもしています(^_^;)
今日の名言
私は新内閣に加わった方々に述べた言葉を、今ここで議会に向かって繰り返したい。
「私の捧げ得るものは、血、労力、涙と汗だけである。」我々は未曾有の大試練に直面して
いる。 我々の前には、長い苦悩と苦闘に年月が横たわっている。
我々の政策は何か、と問われたら、私はこう答えるだろう。「それは、神が与えたまう限りの
あらゆる力を動員して、海上に、陸上に、空中に、戦って戦い抜くことである。人類の罪悪
史上いまだかつて例をみない大暴君を相手に戦い抜くことである。」これが我が国の
政策である。
我が内閣の目的は何か、と問われたら、私はただ一言「勝利!」と答えよう。あらゆる
犠牲を払って勝利を得るのだ。どんな恐ろしい目にあおうと勝利を得るのだ。あらゆる困難を
克服して勝利を得るのだ。勝利なくして、我々の生存はありえないからだ。
ウィンストン・チーチャル
恐怖心は、暴れん坊だが同時に臆病者である。恐怖心を克服するには、
その存在を無視すればよい。あなたにはできるはずだ。
デール・カーネギー
2013年8月17日土曜日
C++ オーバーロード其の弐
今回はオーバーロードとデフォルト引数の関係性についてみていきます。^^
実はオーバーロードを使ってもデフォルト引数を使った場合でも、同じ関数を
複数の方法で呼び出すことができるのです。
具体的には次の例を見てください。
//オーバーロードの場合
double GetCercleArea(double radius, double pi); //プロトタイプ宣言です。
double GetCercleArea(double radius); //これもプロトタイプ宣言です。
:
int main(void)
{
double ans = 0;
//2種類とも呼び出しています
ans = GetCercleArea(20.5, 3.141592);
cout << "ans1 : " << ans << endl;
ans = GetCercleArea(12.5);
cout << "ans2 : " << ans << endl;
:
//デフォルト引数の場合
double GetCercleArea(double radius, double pi = 3.141592); //プロトタイプ宣言です。
:
int main(void)
{
double ans = 0;
//2種類の方法で呼び出しています
ans = GetCercleArea(20.5, 3.141592);
cout << "ans1 : " << ans << endl;
ans = GetCercleArea(12.5);
cout << "ans2 : " << ans << endl;
:
おっと、これではどちらを使ったらよいのか迷ってしまいますね(^_^;)
それでは次にどちらを使うべきかについてみて行きましょう。
もし関数内の処理が1種類でよいときには、デフォルト引数を使うべきです。
例えば2つの値の合計を計算する関数と、3つの値の合計を計算する関数があるとします。
この場合は、計算結果に影響しないようデフォルト引数を0にして関数を定義すれば
ひとまとめにすることができます。^^
//3つめのデフォルト引数が0であることがポイント
double GetTotal(double a, double b, double c = 0)
{
//引数が2つであっても3つであってもどちらでも対応可能です。
return a + b + c;
}
そして、一方2つの値か3つの値のどちらかの平均値を計算する関数がある場合は
適切なデフォルト引数がありませんので、オーバーロードを使用します。
//2つの値の平均値を求める
double GetAverage(double a, double b)
{
return (a + b) / 2;
}
//3つの値の平均値を求める
double GetAverage(double a, double b, double c)
{
return (a + b + c) / 3;
}
このように引数2つのGetAverage()関数と引数3つのGetAverage()関数の
2つを用意します。
間違ってもGetAverage2()、GetAverage3()などという名前で
定義しないよう注意してください。(^_^;)
せっかくのC++の機能が台無しになってしまいますので。
それぞれの使いどころをしっかりとマスターして、上手に使い分けたいものですね^^
今日の名言
恐れおののいている間はまだ災いは本格的でない。勇敢に立ち向かうべきときは、
いよいよ手の下しようがなかったときだ。
ウィンストン・チーチャル
luck(幸運)にPが加わってpluck(勇気)となれば、鬼に金棒である。
作者不明
大きな過ちを多く犯さないうちは、どんな人間でも偉人や善人にはなれない。
ウィリアム・グラッドストン
信念は人を強くする。疑いは活力を麻痺させる。信念は力である。
フレデリック・W・ロバートソン
世界史に残るような偉大で堂々たる業績は、すべて何らかの熱中が
もたらした勝利である。
ラルフ・ワルド・エマーソン
実はオーバーロードを使ってもデフォルト引数を使った場合でも、同じ関数を
複数の方法で呼び出すことができるのです。
具体的には次の例を見てください。
//オーバーロードの場合
double GetCercleArea(double radius, double pi); //プロトタイプ宣言です。
double GetCercleArea(double radius); //これもプロトタイプ宣言です。
:
int main(void)
{
double ans = 0;
//2種類とも呼び出しています
ans = GetCercleArea(20.5, 3.141592);
cout << "ans1 : " << ans << endl;
ans = GetCercleArea(12.5);
cout << "ans2 : " << ans << endl;
:
//デフォルト引数の場合
double GetCercleArea(double radius, double pi = 3.141592); //プロトタイプ宣言です。
:
int main(void)
{
double ans = 0;
//2種類の方法で呼び出しています
ans = GetCercleArea(20.5, 3.141592);
cout << "ans1 : " << ans << endl;
ans = GetCercleArea(12.5);
cout << "ans2 : " << ans << endl;
:
おっと、これではどちらを使ったらよいのか迷ってしまいますね(^_^;)
それでは次にどちらを使うべきかについてみて行きましょう。
もし関数内の処理が1種類でよいときには、デフォルト引数を使うべきです。
例えば2つの値の合計を計算する関数と、3つの値の合計を計算する関数があるとします。
この場合は、計算結果に影響しないようデフォルト引数を0にして関数を定義すれば
ひとまとめにすることができます。^^
//3つめのデフォルト引数が0であることがポイント
double GetTotal(double a, double b, double c = 0)
{
//引数が2つであっても3つであってもどちらでも対応可能です。
return a + b + c;
}
そして、一方2つの値か3つの値のどちらかの平均値を計算する関数がある場合は
適切なデフォルト引数がありませんので、オーバーロードを使用します。
//2つの値の平均値を求める
double GetAverage(double a, double b)
{
return (a + b) / 2;
}
//3つの値の平均値を求める
double GetAverage(double a, double b, double c)
{
return (a + b + c) / 3;
}
このように引数2つのGetAverage()関数と引数3つのGetAverage()関数の
2つを用意します。
間違ってもGetAverage2()、GetAverage3()などという名前で
定義しないよう注意してください。(^_^;)
せっかくのC++の機能が台無しになってしまいますので。
それぞれの使いどころをしっかりとマスターして、上手に使い分けたいものですね^^
今日の名言
恐れおののいている間はまだ災いは本格的でない。勇敢に立ち向かうべきときは、
いよいよ手の下しようがなかったときだ。
ウィンストン・チーチャル
luck(幸運)にPが加わってpluck(勇気)となれば、鬼に金棒である。
作者不明
大きな過ちを多く犯さないうちは、どんな人間でも偉人や善人にはなれない。
ウィリアム・グラッドストン
信念は人を強くする。疑いは活力を麻痺させる。信念は力である。
フレデリック・W・ロバートソン
世界史に残るような偉大で堂々たる業績は、すべて何らかの熱中が
もたらした勝利である。
ラルフ・ワルド・エマーソン
2013年8月16日金曜日
C++ オーバーロード其の壱
C++では、引数の型や数が違う同じ名前の関数を複数定義することができます。
この機能がオーバーロードというものです。
次の例を見てください。^^
同じ名前の関数を複数定義
//第一引数がint型、第二引数がdouble型
double GetCircleArea(int radius, double pi)
{
return radius * radius * pi;
}
//第一引数がdouble型、第二引数がdouble型
double GetCircleArea(double radius, double pi)
{
return radius * radius * pi;
}
//第一引数がdouble型、第二引数なし
double GetCircleArea(double radius)
{
return radius * radius * 3.141592;
}
何と、3つの関数名は全く同じです(^_^;)
C++ではこんなこともできるのですね、さすが「++」だと思います。
C言語では引数が違うだけだと、別の関数名をつけなくてはなりませんでしたね。
GetCircleArea()関数は、どれも円の面積を求める関数です。
それぞれ引数の型や数が違うだけです。
このように同じ機能でパターンの異なる引数を持つ場合に、関数名が1つになるので
便利です。名付け親の悩みがまた1つ解消されますね(^^)
同じ名前の関数が複数ある場合の呼び出し
オーバーロードを使えば、同じ名前の関数を複数定義できます。
これをどのように区別するかというと、コンパイラが引数の型と数を見て、
どの関数を呼び出すのかを決めているのです。
int main(void)
{
int nRad = 20;
double dRad = 20.5;
double dArea = 0;
//第一引数がint型、第二引数がdouble型のGetCircleArea()を呼び出し
dArea = GetCircleArea(nRad, 3.141592);
cout << "area1 : " << dArea << endl;
//第一引数がdouble型、第二引数がdouble型のGetCircleArea()を呼び出し
dArea = GetCircleArea(dRad, 3.141592);
cout << "area2 : " << dArea << endl;
//第一引数がdouble型のGetCircleArea()を呼び出し
dArea = GetCircleArea(dRad);
cout << "area3 : " << dArea << endl;
return 0;
}
実行結果例(ちゃんと呼び分けられていますね^^)
# ./test
area1 : 1256.64
area2 : 1320.25
area3 : 1320.25
オーバーロード使用時の注意点
戻り値の型だけが違う関数は、オーバーロードできません。
//OK(戻り値と引数が異なっている)
double GetCircleArea(double radius, double pi);int GetCircleArea(int radius, double pi);
//NG(戻り値だけが異なっている)
double GetCircleArea(double radius, double pi);int GetCircleArea(double radius, double pi);
NGの場合を試してみると分かりますが、コンパイルエラーになります。(^_^;)
error: new declaration ‘int GetCircleArea(double, double)’
error: ambiguates old declaration ‘double GetCircleArea(double, double)’
今日の名言
目の前に多くの困難が横たわっていると、つい身をかわして他の者に仕事を変わって
もらおうという気になりがちだが、私はそんな卑怯なやり方はごめんだ。自分の職務に
踏みとどまって義務を果たすためにがんばりとおす覚悟だ。
ウィンストン・チーチャル
恐怖と悩みを克服するには、脇目もふらずに働くことだ!!
デール・カーネギー
何事かを試みて失敗するものと、何事も試みないで成功するものとの間には、
計り知れない相違がある。
ロイド・ジョーンズ
この機能がオーバーロードというものです。
次の例を見てください。^^
同じ名前の関数を複数定義
//第一引数がint型、第二引数がdouble型
double GetCircleArea(int radius, double pi)
{
return radius * radius * pi;
}
//第一引数がdouble型、第二引数がdouble型
double GetCircleArea(double radius, double pi)
{
return radius * radius * pi;
}
//第一引数がdouble型、第二引数なし
double GetCircleArea(double radius)
{
return radius * radius * 3.141592;
}
何と、3つの関数名は全く同じです(^_^;)
C++ではこんなこともできるのですね、さすが「++」だと思います。
C言語では引数が違うだけだと、別の関数名をつけなくてはなりませんでしたね。
GetCircleArea()関数は、どれも円の面積を求める関数です。
それぞれ引数の型や数が違うだけです。
このように同じ機能でパターンの異なる引数を持つ場合に、関数名が1つになるので
便利です。名付け親の悩みがまた1つ解消されますね(^^)
同じ名前の関数が複数ある場合の呼び出し
オーバーロードを使えば、同じ名前の関数を複数定義できます。
これをどのように区別するかというと、コンパイラが引数の型と数を見て、
どの関数を呼び出すのかを決めているのです。
int main(void)
{
int nRad = 20;
double dRad = 20.5;
double dArea = 0;
//第一引数がint型、第二引数がdouble型のGetCircleArea()を呼び出し
dArea = GetCircleArea(nRad, 3.141592);
cout << "area1 : " << dArea << endl;
//第一引数がdouble型、第二引数がdouble型のGetCircleArea()を呼び出し
dArea = GetCircleArea(dRad, 3.141592);
cout << "area2 : " << dArea << endl;
//第一引数がdouble型のGetCircleArea()を呼び出し
dArea = GetCircleArea(dRad);
cout << "area3 : " << dArea << endl;
return 0;
}
実行結果例(ちゃんと呼び分けられていますね^^)
# ./test
area1 : 1256.64
area2 : 1320.25
area3 : 1320.25
オーバーロード使用時の注意点
戻り値の型だけが違う関数は、オーバーロードできません。
//OK(戻り値と引数が異なっている)
double GetCircleArea(double radius, double pi);int GetCircleArea(int radius, double pi);
//NG(戻り値だけが異なっている)
double GetCircleArea(double radius, double pi);int GetCircleArea(double radius, double pi);
NGの場合を試してみると分かりますが、コンパイルエラーになります。(^_^;)
error: new declaration ‘int GetCircleArea(double, double)’
error: ambiguates old declaration ‘double GetCircleArea(double, double)’
今日の名言
目の前に多くの困難が横たわっていると、つい身をかわして他の者に仕事を変わって
もらおうという気になりがちだが、私はそんな卑怯なやり方はごめんだ。自分の職務に
踏みとどまって義務を果たすためにがんばりとおす覚悟だ。
ウィンストン・チーチャル
恐怖と悩みを克服するには、脇目もふらずに働くことだ!!
デール・カーネギー
何事かを試みて失敗するものと、何事も試みないで成功するものとの間には、
計り知れない相違がある。
ロイド・ジョーンズ
2013年8月15日木曜日
C++関数のデフォルト引数とは
C++では、関数の引数にデフォルト引数を設定出来ます。^^
次の例を見てください。
デフォルト引数の設定と呼び出し
プロトタイプ宣言で設定する場合(radius = 2, pi = 3.141592がデフォルト値です)
double GetCircleArea(int radius = 2, double pi = 3.141592);
なお、プロトタイプ宣言で設定しなかった場合は、関数定義でも設定できます。
関数定義で設定する場合(radius = 5, pi = 3,1415がデフォルト値です)
double GetCircleArea(int radius, double pi); //普通のプロトタイプ宣言
:
double GetCircleArea(int radius = 5, double pi = 3.1415) //関数定義
{
return radius * radius * pi;
}
実際の呼び出し例
デフォルト値が設定してあれば、引数を省略して呼び出すことができます。
これは、プロトタイプ宣言で設定してある場合です。
int main(void)
{
double area = 0;
area = GetCircleArea(); //GetCircleArea(2, 3.141592); と同じです。
cout << "area1 : " << area << endl;
area = GetCircleArea(3); //GetCircleArea(3, 3.141592); と同じです。
cout << "area2 : " << area << endl;
area = GetCircleArea(12, 3.14); //GetCircleArea(12, 3.141592); と同じです。
cout << "area3 : " << area << endl;
:
}
実行結果例
# ./test
area1 : 12.5664
area2 : 28.2743
area3 : 452.16
:
デフォルト引数設定時の注意点
デフォルト値は、すべての引数に設定する必要はありません。
double GetCircleArea(int radius, double pi = 3.141592); //pi にだけ設定
しかし、最初の引数だけにデフォルト値を設定することができません。(^_^;)
デフォルト値は最後の引数から順番に設定していく必要があります。
//最後の引数を飛ばして、radius にデフォルト値15を設定してみます。
double GetCircleArea(int radius = 15, double pi);
すると、コンパイルエラーになります。
error: default argument missing for parameter 2 of ‘double GetCircleArea(int, double)’
関数呼び出し時の注意点
デフォルト引数を持つ関数を呼び出すときは、ある引数を省略するとそれ以降の
引数は全て省略したとみなされます。
例えば、次のように最初の引数だけを省略することができません。
//最初の引数radiusの引数を省略して2番めの引数piだけを設定してみます。
double GetCircleArea(, 3.14);
すると、コンパイルエラーになります。
error: default argument missing for parameter 2 of ‘double GetCircleArea(int, double)’
In function ‘int main()’:
error: expected primary-expression before ‘,’ token
どういう時に使えるかというと、
ほぼ毎回同じ値なんだけど、たまには変更したい という時です。(^^)
こんな時にはデフォルト引数が便利ですね。
今日の名言
「もし太陽と月が己を疑えば、直ちに消え去るだろう」詩人である私は、このウィリアム・
ブレイクの詩が自分の作品であったら、とよく思ったものである。私は、計画に着手できない
生徒たちがいたら、よくこの詩をを引き合いに出して激励したものだ。自分自身を信ずることは
他のすべての信念の中心部分である。自信がなくなれば、人生は動きが取れなくなる。
もちろん、誰でも神経が高ぶる時がある。舞台に立ったり講演したりした経験のある者なら、
いよいよとなって「あがる」とはどんなものであるか、よく知っている。最上の俳優は幕が上がる
前に一番「あがる」と言われている。セリフを忘れるかもしれない、何かの手違いが起こるかも
しれない。-しかしいざ劇が始まると、スラスラと進行するのが常である。
これと同様に、ことを目前にして自信がなくなる事態は、ありとあらゆる人間活動に伴う。
作戦の実施、詩人の作詞、セールスマンの初仕事、花嫁の初料理など、皆そうである。
しかし、誰も彼もが失敗を恐れて行動を避けていたなら、何事も決して成し遂げられない。
自分自身の能力が信じられないのは、あらゆる人間活動には、必ず他人の賞賛や叱責が
大きく関係しているからだ。我々は理想的目標を立て、とても無理だと言って呻くのである。
しかし本来世の中が不完全なのに、完成ばかり目指すのは危険である。最上の方法は、
迷わずに目の前の仕事に着手することだ。戦闘の結果がどうなるか、ケーキの焼け具合が
どうなるかは、未来の手に任せれば良い。もし本当に最善を尽くしていれば、失敗を気に
かける暇などなくなる。
ロバート・ヒリヤー
次の例を見てください。
デフォルト引数の設定と呼び出し
プロトタイプ宣言で設定する場合(radius = 2, pi = 3.141592がデフォルト値です)
double GetCircleArea(int radius = 2, double pi = 3.141592);
なお、プロトタイプ宣言で設定しなかった場合は、関数定義でも設定できます。
関数定義で設定する場合(radius = 5, pi = 3,1415がデフォルト値です)
double GetCircleArea(int radius, double pi); //普通のプロトタイプ宣言
:
double GetCircleArea(int radius = 5, double pi = 3.1415) //関数定義
{
return radius * radius * pi;
}
実際の呼び出し例
デフォルト値が設定してあれば、引数を省略して呼び出すことができます。
これは、プロトタイプ宣言で設定してある場合です。
int main(void)
{
double area = 0;
area = GetCircleArea(); //GetCircleArea(2, 3.141592); と同じです。
cout << "area1 : " << area << endl;
area = GetCircleArea(3); //GetCircleArea(3, 3.141592); と同じです。
cout << "area2 : " << area << endl;
area = GetCircleArea(12, 3.14); //GetCircleArea(12, 3.141592); と同じです。
cout << "area3 : " << area << endl;
:
}
実行結果例
# ./test
area1 : 12.5664
area2 : 28.2743
area3 : 452.16
:
デフォルト引数設定時の注意点
デフォルト値は、すべての引数に設定する必要はありません。
double GetCircleArea(int radius, double pi = 3.141592); //pi にだけ設定
しかし、最初の引数だけにデフォルト値を設定することができません。(^_^;)
デフォルト値は最後の引数から順番に設定していく必要があります。
//最後の引数を飛ばして、radius にデフォルト値15を設定してみます。
double GetCircleArea(int radius = 15, double pi);
すると、コンパイルエラーになります。
error: default argument missing for parameter 2 of ‘double GetCircleArea(int, double)’
関数呼び出し時の注意点
デフォルト引数を持つ関数を呼び出すときは、ある引数を省略するとそれ以降の
引数は全て省略したとみなされます。
例えば、次のように最初の引数だけを省略することができません。
//最初の引数radiusの引数を省略して2番めの引数piだけを設定してみます。
double GetCircleArea(, 3.14);
すると、コンパイルエラーになります。
error: default argument missing for parameter 2 of ‘double GetCircleArea(int, double)’
In function ‘int main()’:
error: expected primary-expression before ‘,’ token
どういう時に使えるかというと、
ほぼ毎回同じ値なんだけど、たまには変更したい という時です。(^^)
こんな時にはデフォルト引数が便利ですね。
今日の名言
「もし太陽と月が己を疑えば、直ちに消え去るだろう」詩人である私は、このウィリアム・
ブレイクの詩が自分の作品であったら、とよく思ったものである。私は、計画に着手できない
生徒たちがいたら、よくこの詩をを引き合いに出して激励したものだ。自分自身を信ずることは
他のすべての信念の中心部分である。自信がなくなれば、人生は動きが取れなくなる。
もちろん、誰でも神経が高ぶる時がある。舞台に立ったり講演したりした経験のある者なら、
いよいよとなって「あがる」とはどんなものであるか、よく知っている。最上の俳優は幕が上がる
前に一番「あがる」と言われている。セリフを忘れるかもしれない、何かの手違いが起こるかも
しれない。-しかしいざ劇が始まると、スラスラと進行するのが常である。
これと同様に、ことを目前にして自信がなくなる事態は、ありとあらゆる人間活動に伴う。
作戦の実施、詩人の作詞、セールスマンの初仕事、花嫁の初料理など、皆そうである。
しかし、誰も彼もが失敗を恐れて行動を避けていたなら、何事も決して成し遂げられない。
自分自身の能力が信じられないのは、あらゆる人間活動には、必ず他人の賞賛や叱責が
大きく関係しているからだ。我々は理想的目標を立て、とても無理だと言って呻くのである。
しかし本来世の中が不完全なのに、完成ばかり目指すのは危険である。最上の方法は、
迷わずに目の前の仕事に着手することだ。戦闘の結果がどうなるか、ケーキの焼け具合が
どうなるかは、未来の手に任せれば良い。もし本当に最善を尽くしていれば、失敗を気に
かける暇などなくなる。
ロバート・ヒリヤー
2013年8月13日火曜日
列挙型の話
列挙型(enum 読み方はイナム、イーナムどっちでも^^)は、整数に名前をつけて
プログラムをわかりやすくすることができる機能です。
使い方は次のようになります。
enum Colors { //赤橙黄緑青藍紫 虹色(^^)v
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
};
C言語とC++言語の列挙型との違いは列挙型変数の宣言方法です。
例えばC言語では次のような書き方でした。
enum Colors PenColor;
しかし、C++言語では、列挙型変数の宣言するときにenumという記述が不要に
なりました。具体的にはこのようになります。
Colors PenColor;
一瞬構造体か?などと思ってしまいますね(^_^;)
列挙型の要素の値は、0, 1, 2, 3, ... と増えていきます。また途中で任意の数を指定すると
その数から順に1ずつ増えていく形になります。
enum Colors { //通常の虹色(^^)v
Red, //0
Orange, //1
Yellow, //2
Green, //3
Blue, //4
Indigo, //5
Violet //6
};
enum Colors { //少し変わった虹色2(^^)v
Red, //0
Orange = 12, //12
Yellow, //13
Green, //14
Blue = 25, //25
Indigo, //26
Violet //27
};
予告
プログラムを作成しながら、時々関数の引数だけ変えたいと思ったことはないでしょうか?
C++ではこんな場合でも便利な機能があります。それは引数にデフォルト値を設定する
方法です。デフォルト値が設定されていれば、値を設定しなくても呼び出すことができます。
今仮に、円の面積を計算する関数があったとして、円周率を指定する引数をデフォルト値で
3.141592を設定したとします。この場合円周率を指定せずに呼び出すとデフォルト値である
3.141592が円の面積計算で使われます。そして、一方、円周率に3を設定した場合は
円周率が3として円の面積を計算します。
このように、ほぼ同じ処理なんだけど引数が少し変わることもある、という場面では
デフォルト引数を設定しておくと便利ですし、コードが読みやすくもなります。
また、引数の型や数が違えば、別の関数に同じ名前をつけることもできます。
これはオーバーロードといいます。紛らわしい単語にオーバーライドというのもあります^^
Cでは同じ「大きい方の数値を返す関数」でもint用、double用などと別名で分けなければ
なりませんでした。しかし、C++では関数は同じ名前にできますので、よりシンプルな
コードを書くことができます。
予告2
Cでは、使用する2つのライブラリに同じ名前の関数や変数がある場合、コンパイル、
リンクでエラーになっていたかと思います。その場合ヘッダファイルの編集で解決出来れば
良いですが、大抵は「衝突を防ぐためライブラリを使用しない」というやむなしの消極的
対応しかできなかったのではないでしょうか(^_^;)
C++では関数名や変数名の重複をあらかじめ防ぐ手段が追加されています。
それには名前空間(namespace)という方法を使います。
名前空間を使用することで、関数や変数の有効範囲を限定できるのです。
例えばRedという名前空間とOrangeという名前空間に、それぞれ同じSetPenColor()という
関数があっても問題ありません。SetPenColor()関数を使うときに、どの名前空間に属する
SetPenColor()関数を使うかだけを意識すればよいのです。
名前空間を使えば他と名前が被ってしまうことを気にしないで済むようになります。
余計なことに頭を悩ませる必要がなくなりますね(^^)
次回以降で名前空間と関係するスコープ解決演算子やプログラム実行時の
入出力オブジェクト、引数付きマクロに似ているインライン関数について
見ていきます。 できることが増え一層楽しくなってくるかと思います(^^)
今日の名言
人間は死を恐れるべきではない。こう言えるのは、私が死に何度も直面したからである。
その体験は全く快いものだ。耳には美しい音楽が聞こえ、全ては甘美で静寂である。
もがき苦しむことも恐怖もない。死に直面すれば、これほど容易でこれほど幸福な経験は
生まれて初めてだ、ということが分かる。
エディー・リッケンバッカー
いくら知恵があっても、これを使う勇気がなければ何の役にも立たないように、いくら
信仰が厚くても、希望がなければ何の価値もない。希望はいつまでも人とともにあって
悪と不幸を克服するからである。
マルティン・ルター
事前にあわてふためいて、あとは悠然と構えているほうが、事前に悠然と構えていて、
事が起こった時にあわてふためくよりも、利口な場合がある。
ウィンストン・チャーチル
プログラムをわかりやすくすることができる機能です。
使い方は次のようになります。
enum Colors { //赤橙黄緑青藍紫 虹色(^^)v
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
};
C言語とC++言語の列挙型との違いは列挙型変数の宣言方法です。
例えばC言語では次のような書き方でした。
enum Colors PenColor;
しかし、C++言語では、列挙型変数の宣言するときにenumという記述が不要に
なりました。具体的にはこのようになります。
Colors PenColor;
一瞬構造体か?などと思ってしまいますね(^_^;)
列挙型の要素の値は、0, 1, 2, 3, ... と増えていきます。また途中で任意の数を指定すると
その数から順に1ずつ増えていく形になります。
enum Colors { //通常の虹色(^^)v
Red, //0
Orange, //1
Yellow, //2
Green, //3
Blue, //4
Indigo, //5
Violet //6
};
enum Colors { //少し変わった虹色2(^^)v
Red, //0
Orange = 12, //12
Yellow, //13
Green, //14
Blue = 25, //25
Indigo, //26
Violet //27
};
予告
プログラムを作成しながら、時々関数の引数だけ変えたいと思ったことはないでしょうか?
C++ではこんな場合でも便利な機能があります。それは引数にデフォルト値を設定する
方法です。デフォルト値が設定されていれば、値を設定しなくても呼び出すことができます。
今仮に、円の面積を計算する関数があったとして、円周率を指定する引数をデフォルト値で
3.141592を設定したとします。この場合円周率を指定せずに呼び出すとデフォルト値である
3.141592が円の面積計算で使われます。そして、一方、円周率に3を設定した場合は
円周率が3として円の面積を計算します。
このように、ほぼ同じ処理なんだけど引数が少し変わることもある、という場面では
デフォルト引数を設定しておくと便利ですし、コードが読みやすくもなります。
また、引数の型や数が違えば、別の関数に同じ名前をつけることもできます。
これはオーバーロードといいます。紛らわしい単語にオーバーライドというのもあります^^
Cでは同じ「大きい方の数値を返す関数」でもint用、double用などと別名で分けなければ
なりませんでした。しかし、C++では関数は同じ名前にできますので、よりシンプルな
コードを書くことができます。
予告2
Cでは、使用する2つのライブラリに同じ名前の関数や変数がある場合、コンパイル、
リンクでエラーになっていたかと思います。その場合ヘッダファイルの編集で解決出来れば
良いですが、大抵は「衝突を防ぐためライブラリを使用しない」というやむなしの消極的
対応しかできなかったのではないでしょうか(^_^;)
C++では関数名や変数名の重複をあらかじめ防ぐ手段が追加されています。
それには名前空間(namespace)という方法を使います。
名前空間を使用することで、関数や変数の有効範囲を限定できるのです。
例えばRedという名前空間とOrangeという名前空間に、それぞれ同じSetPenColor()という
関数があっても問題ありません。SetPenColor()関数を使うときに、どの名前空間に属する
SetPenColor()関数を使うかだけを意識すればよいのです。
名前空間を使えば他と名前が被ってしまうことを気にしないで済むようになります。
余計なことに頭を悩ませる必要がなくなりますね(^^)
次回以降で名前空間と関係するスコープ解決演算子やプログラム実行時の
入出力オブジェクト、引数付きマクロに似ているインライン関数について
見ていきます。 できることが増え一層楽しくなってくるかと思います(^^)
今日の名言
人間は死を恐れるべきではない。こう言えるのは、私が死に何度も直面したからである。
その体験は全く快いものだ。耳には美しい音楽が聞こえ、全ては甘美で静寂である。
もがき苦しむことも恐怖もない。死に直面すれば、これほど容易でこれほど幸福な経験は
生まれて初めてだ、ということが分かる。
エディー・リッケンバッカー
いくら知恵があっても、これを使う勇気がなければ何の役にも立たないように、いくら
信仰が厚くても、希望がなければ何の価値もない。希望はいつまでも人とともにあって
悪と不幸を克服するからである。
マルティン・ルター
事前にあわてふためいて、あとは悠然と構えているほうが、事前に悠然と構えていて、
事が起こった時にあわてふためくよりも、利口な場合がある。
ウィンストン・チャーチル
2013年8月11日日曜日
C++定数の宣言
出ました、定数を宣言するには const を使用します。
const とは?
変数に const を付けて宣言することで、定数になります。
すると、初期化以外では値の代入ができなくなります。
これはCでもC++でも共通です。
:
const int number1 = 10; //定数number1を宣言、初期値は10
:
number1 = 3; //number1に値を代入しようとすると
: //コンパイルエラーです(^_^;)
#defineの代わりに使用出来ます
C++の const は、Cのconstに比べて機能が拡張されており、Cの#defineで
数値を定義するような場面で、代わりに使うことができます。
Cでは、配列のサイズを定義するときに#defineを使っていました。
:
#define BUFFSIZE 10
int main(void)
{
int Array[BUFFSIZE]; //コンパイル前にBUFFSIZEは10に置き換わります
:
同様のことをC++ではconstで実現出来ます。
:
int main(void)
{
const int BUFFSIZE = 10; //定数BUFFSIZEを宣言、初期値は10
int Array[BUFFSIZE]; //Arrayのサイズはモチロン10です
:
ちなみに、これはCではコンパイルエラーになります(^_^;)
constのメリット
#defineを使うような場面でも、constを使うことをオススメします。
また、関数の引数を定数にすることもできます。
関数の宣言で引数にconstをつけると、引数の値を間違えて変更してしまうのを
防ぐことができます。例えば次のプログラムはコンパイルエラーになります。
void DisplayNumber(const int number) //引数numberを定数にします
{
number = 3; //コンパイルエラーで、実行出来ません(^_^;)
}
ポインタにconstを指定したときは、その指し示す先の値が定数になります。
次の例を見てください。
#include <stdio.h>
#include <string.h>
void DisplayString(const char *pstr) //ポインタpstrの指す先の値はconst
{
strcpy(pstr, "this is a cat."); //pstrに文字列をコピーしようとすると
} //コンパイルエラーになります(^_^;)
int main(void)
{
char *buff = "this is a dog."
DisplayString(buff);
return 0;
}
C言語では警告は出るものの、実行できてしまいました(;´∀`)
関数の中で値を変更しない場合は、引数をconstにしておくことがオススメです。
constにしておけば、間違えて引数の値を変更してしまうことを防げます。
const指定したポインタ使用時の注意点
const指定をしたchar型のポインタpstrを通常のポインタに代入しようとすると
どうなるかをみていきましょう。
:
void ChangeStr(const char *pstr)
{
char *buff; //char型のポインタ変数です
buff = pstr; //const指定したポインタ変数pstrを
} //ポインタ変数buffに代入しようとすると
: //コンパイルエラーになりますです(^_^;)
const指定したポインタを、const指定していないポインタに代入しようとすると
コンパイルでエラーになってしまします。
なぜなら、もし代入できてしまうと、次のようにconst指定したポインタの内容が
書き換えられてしまうからです。
:
void ChangeStr(const char *pstr)
{
char *buff;
buff = pstr;
buff[0] = 'a'; //もしbuff[0]を'a'にできるとするとpstr[0]も
} //'a'になってしまします!!
:
C++では、当然コンパイルエラーになります。
buffポインタを使用してconst宣言した筈の pstr の内容を書き換えられてしまっては
大問題ですね(^_^;)
そのため、「const指定したポインタを通常のポインタに代入できない」という
お約束があるのです。
constをうまくつかってミスのないプログラムを作成したいものですね^^
今日の名言
人に望まれ賞賛される勇気は、美しく死ぬ勇気ではなく、男らしく生きる勇気である。
トーマス・カーライル
苦しみを恐れるものは、その恐怖だけですでに苦しんでいる。
ミシェル・エケム・ド・モンテーニュ
行動は必ずしも幸福をもたらさないかもしれないが、行動のないところに幸福は生まれない。
ベンジャミン・ディズレーリ
const とは?
変数に const を付けて宣言することで、定数になります。
すると、初期化以外では値の代入ができなくなります。
これはCでもC++でも共通です。
:
const int number1 = 10; //定数number1を宣言、初期値は10
:
number1 = 3; //number1に値を代入しようとすると
: //コンパイルエラーです(^_^;)
#defineの代わりに使用出来ます
C++の const は、Cのconstに比べて機能が拡張されており、Cの#defineで
数値を定義するような場面で、代わりに使うことができます。
Cでは、配列のサイズを定義するときに#defineを使っていました。
:
#define BUFFSIZE 10
int main(void)
{
int Array[BUFFSIZE]; //コンパイル前にBUFFSIZEは10に置き換わります
:
同様のことをC++ではconstで実現出来ます。
:
int main(void)
{
const int BUFFSIZE = 10; //定数BUFFSIZEを宣言、初期値は10
int Array[BUFFSIZE]; //Arrayのサイズはモチロン10です
:
ちなみに、これはCではコンパイルエラーになります(^_^;)
constのメリット
#defineを使うような場面でも、constを使うことをオススメします。
- constなら型が指定できるので、コード記述時のミスを予防できる
- デバッグ時に#defineの値を表示できないことがある
また、関数の引数を定数にすることもできます。
関数の宣言で引数にconstをつけると、引数の値を間違えて変更してしまうのを
防ぐことができます。例えば次のプログラムはコンパイルエラーになります。
void DisplayNumber(const int number) //引数numberを定数にします
{
number = 3; //コンパイルエラーで、実行出来ません(^_^;)
}
ポインタにconstを指定したときは、その指し示す先の値が定数になります。
次の例を見てください。
#include <stdio.h>
#include <string.h>
void DisplayString(const char *pstr) //ポインタpstrの指す先の値はconst
{
strcpy(pstr, "this is a cat."); //pstrに文字列をコピーしようとすると
} //コンパイルエラーになります(^_^;)
int main(void)
{
char *buff = "this is a dog."
DisplayString(buff);
return 0;
}
C言語では警告は出るものの、実行できてしまいました(;´∀`)
関数の中で値を変更しない場合は、引数をconstにしておくことがオススメです。
constにしておけば、間違えて引数の値を変更してしまうことを防げます。
const指定したポインタ使用時の注意点
const指定をしたchar型のポインタpstrを通常のポインタに代入しようとすると
どうなるかをみていきましょう。
:
void ChangeStr(const char *pstr)
{
char *buff; //char型のポインタ変数です
buff = pstr; //const指定したポインタ変数pstrを
} //ポインタ変数buffに代入しようとすると
: //コンパイルエラーになりますです(^_^;)
const指定したポインタを、const指定していないポインタに代入しようとすると
コンパイルでエラーになってしまします。
なぜなら、もし代入できてしまうと、次のようにconst指定したポインタの内容が
書き換えられてしまうからです。
:
void ChangeStr(const char *pstr)
{
char *buff;
buff = pstr;
buff[0] = 'a'; //もしbuff[0]を'a'にできるとするとpstr[0]も
} //'a'になってしまします!!
:
C++では、当然コンパイルエラーになります。
buffポインタを使用してconst宣言した筈の pstr の内容を書き換えられてしまっては
大問題ですね(^_^;)
そのため、「const指定したポインタを通常のポインタに代入できない」という
お約束があるのです。
constをうまくつかってミスのないプログラムを作成したいものですね^^
今日の名言
人に望まれ賞賛される勇気は、美しく死ぬ勇気ではなく、男らしく生きる勇気である。
トーマス・カーライル
苦しみを恐れるものは、その恐怖だけですでに苦しんでいる。
ミシェル・エケム・ド・モンテーニュ
行動は必ずしも幸福をもたらさないかもしれないが、行動のないところに幸福は生まれない。
ベンジャミン・ディズレーリ
C++制御文での変数宣言
C++では変数宣言は制御文の中でもできるようになっています。
もっともよく見かけるのはカウンタ変数をfor文の中で宣言しているパターンでしょう^^
C言語のようにブロックの先頭でカウンタ変数を宣言しなくても、
まとめてかけるので便利です。
for (int i = 0; i < 3; i++) { //カウンタ変数 i の宣言と初期化を同時にしています。
:
見た目に分かりやすいのではないでしょうか。
では実際のプログラムで具体的に見てみましょう。
プログラム例1
#include <iostream>
using namespace std;
int main(void)
{
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << i * i << "ですわ!" << endl;
}
return 0;
}
実行結果1
# ./test
1の2乗は1ですわ!
2の2乗は4ですわ!
3の2乗は9ですわ!
4の2乗は16ですわ!
5の2乗は25ですわ!
1から5までの2乗を順に表示しました。
この実行結果についてですが、表示のズレが気になるなと思った方も
いるのではないでしょうか?
そこで表示にこだわったプログラムについて少しだけ試してみたいと思います。
C++ではマニピュレータによる書式設定という方法がありますので、
今回はこれを使用します。 iomanipというヘッダをインクルードする必要があります。
そしてこの場合2乗の数字が最大2桁ですので、あらかじめ2桁表示になるよう
設定してみます。
使用するマニピュレータは、 setw() です。出力時の幅を指定することができます。
プログラム例2
#include <iostream>
#include <iomanip>
using namespace std;
int main(void)
{
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << setw(2) << i * i << "ですわ!" << endl;
}
return 0;
}
実行結果2
# ./test
1の2乗は 1ですわ!
2の2乗は 4ですわ!
3の2乗は 9ですわ!
4の2乗は16ですわ!
5の2乗は25ですわ!
おぉ、見事に揃いました(^^)
空白では気持ち悪いという方、今度は2桁表示指定で頭をゼロ埋めしてみます^^
その場合はさらにsetfill()を使います。
プログラム例3
:
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << setfill('0') << setw(2) << i * i << "ですわ!" << endl;
}
:
実行結果3
# ./test
1の2乗は01ですわ!
2の2乗は04ですわ!
3の2乗は09ですわ!
4の2乗は16ですわ!
5の2乗は25ですわ!
ちょっと遊んでしまいました(^_^;)
どうでしょう?Cの書式指定と比べて、断然覚えづらいですね(;´∀`)
書式指定についてはいずれ詳しくまとめたいと思います。
カウンタの有効範囲について
for文の中で宣言したカウンタ変数の有効範囲(スコープと言います)は、
コンパイラによって違いがあります。
最近の多くのコンパイラでは、カウンタ変数を宣言したfor文の中だけが
有効範囲になります。
有効範囲がfor文の中のみ
:
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << i * i << "ですわ!" << endl;
}//カウンタ変数 i の有効範囲はここまで
cout << "さらに続きで6以降を計算しよう。" << endl;
for (int j = 6; j <= 10; j++) {
cout << j << "の2乗は" << j * j << "です。" << endl;
}//そしてカウンタ変数 j の有効範囲はここまで
:
しかし、コンパイラによっては、有効範囲がfor文の外側のブロック内にまで
及ぶ場合があります。
有効範囲がfor文の外側のブロック内
int main(void)
{
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << i * i << "ですわ!" << endl;
}
cout << "forループの外側です。" << endl;
return 0;//カウンタ変数 i の有効範囲はここまで
}
外側にまで及ぶのはVisualC++というコンパイラではデフォルトのようです。
このブログでは使っていませんが、もしVisualStudioなどで環境構築している場合、
念のため自分のコンパイラがどちらなのか、把握しておくとよいでしょうね。
今日の名言
今度、何か手の付けられないような困難に出会ったら、思い切ってその中に飛び込み
不可能と思っていたことを可能にすることだ。自分の能力を完全に信頼していれば、
必ずやれる。
デール・カーネギー
自信は大事業を行うための一番の必要条件である。
サミュエル・ジョンソン
大事のためには、いつ何時でも自分の肉体、安寧、命さえも投げ打つ心構えのない者は
何の値打ちもない人間だ。
セオドア・ルーズヴェルト
もっともよく見かけるのはカウンタ変数をfor文の中で宣言しているパターンでしょう^^
C言語のようにブロックの先頭でカウンタ変数を宣言しなくても、
まとめてかけるので便利です。
for (int i = 0; i < 3; i++) { //カウンタ変数 i の宣言と初期化を同時にしています。
:
見た目に分かりやすいのではないでしょうか。
では実際のプログラムで具体的に見てみましょう。
プログラム例1
#include <iostream>
using namespace std;
int main(void)
{
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << i * i << "ですわ!" << endl;
}
return 0;
}
実行結果1
# ./test
1の2乗は1ですわ!
2の2乗は4ですわ!
3の2乗は9ですわ!
4の2乗は16ですわ!
5の2乗は25ですわ!
1から5までの2乗を順に表示しました。
この実行結果についてですが、表示のズレが気になるなと思った方も
いるのではないでしょうか?
そこで表示にこだわったプログラムについて少しだけ試してみたいと思います。
C++ではマニピュレータによる書式設定という方法がありますので、
今回はこれを使用します。 iomanipというヘッダをインクルードする必要があります。
そしてこの場合2乗の数字が最大2桁ですので、あらかじめ2桁表示になるよう
設定してみます。
使用するマニピュレータは、 setw() です。出力時の幅を指定することができます。
プログラム例2
#include <iostream>
#include <iomanip>
using namespace std;
int main(void)
{
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << setw(2) << i * i << "ですわ!" << endl;
}
return 0;
}
実行結果2
# ./test
1の2乗は 1ですわ!
2の2乗は 4ですわ!
3の2乗は 9ですわ!
4の2乗は16ですわ!
5の2乗は25ですわ!
おぉ、見事に揃いました(^^)
空白では気持ち悪いという方、今度は2桁表示指定で頭をゼロ埋めしてみます^^
その場合はさらにsetfill()を使います。
プログラム例3
:
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << setfill('0') << setw(2) << i * i << "ですわ!" << endl;
}
:
実行結果3
# ./test
1の2乗は01ですわ!
2の2乗は04ですわ!
3の2乗は09ですわ!
4の2乗は16ですわ!
5の2乗は25ですわ!
ちょっと遊んでしまいました(^_^;)
どうでしょう?Cの書式指定と比べて、断然覚えづらいですね(;´∀`)
書式指定についてはいずれ詳しくまとめたいと思います。
カウンタの有効範囲について
for文の中で宣言したカウンタ変数の有効範囲(スコープと言います)は、
コンパイラによって違いがあります。
最近の多くのコンパイラでは、カウンタ変数を宣言したfor文の中だけが
有効範囲になります。
有効範囲がfor文の中のみ
:
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << i * i << "ですわ!" << endl;
}//カウンタ変数 i の有効範囲はここまで
cout << "さらに続きで6以降を計算しよう。" << endl;
for (int j = 6; j <= 10; j++) {
cout << j << "の2乗は" << j * j << "です。" << endl;
}//そしてカウンタ変数 j の有効範囲はここまで
:
しかし、コンパイラによっては、有効範囲がfor文の外側のブロック内にまで
及ぶ場合があります。
有効範囲がfor文の外側のブロック内
int main(void)
{
for (int i = 1; i <= 5; i++) {
cout << i << "の2乗は" << i * i << "ですわ!" << endl;
}
cout << "forループの外側です。" << endl;
return 0;//カウンタ変数 i の有効範囲はここまで
}
外側にまで及ぶのはVisualC++というコンパイラではデフォルトのようです。
このブログでは使っていませんが、もしVisualStudioなどで環境構築している場合、
念のため自分のコンパイラがどちらなのか、把握しておくとよいでしょうね。
今日の名言
今度、何か手の付けられないような困難に出会ったら、思い切ってその中に飛び込み
不可能と思っていたことを可能にすることだ。自分の能力を完全に信頼していれば、
必ずやれる。
デール・カーネギー
自信は大事業を行うための一番の必要条件である。
サミュエル・ジョンソン
大事のためには、いつ何時でも自分の肉体、安寧、命さえも投げ打つ心構えのない者は
何の値打ちもない人間だ。
セオドア・ルーズヴェルト
C++変数宣言の位置
C++ではブロック内のどこでも変数宣言が出来ると書きました。
使う前なら、どこでも自由に宣言できるのです。
それでは、変数を宣言する位置ついて詳しく見て行きましょう。
今、2つの変数の値を交換する関数を例に、変数を宣言する位置を見てみましょう。
void SwapFunction(int *a, inb *b)
{
if (*a == *b) {
return;
}
int buf = *a; //ここで変数bufを宣言しています
*a = *b;
*b = buf;
return;
}
変数bufはSwapFunction()関数のブロックの途中で宣言されています。
そして、宣言と同時に初期化もしています。
変数宣言は使う直前がオススメです
変数の宣言は、使う直前にするようにしましょう。
そうでないと宣言が無駄になることもありますし、読みやすさに違いが出てきます。
では、試しにSwapFunction()関数のはじめで変数bufを宣言してみます。
void SwapFunction(int *a, int *b)
{
int buf; //ここで変数bufを宣言しています
if (*a == *b) {
return; //*a == *b なら何もせずに、returnします
}
buf = *a; //ここは *a == *b の時には実行されません
*a = *b;
*b = buf;
return;
}
使わないかもしれない変数をあらかじめ宣言しておくのは、無駄になってしまいます。(^_^;)
どうでしょうか、使う直前に宣言したほうが見やすくありませんか?
しかし、この場合途中リターンが見た目気持ち悪いという方もいるかもしれません。(^_^;)
もっとスマートに書くならこんな感じでしょうか?
お好みでどうぞ^^
こんなサンプルプログラムでも洗練させてみるのも面白いものですよ。
void SwapFunctionPart2(int *a, int *b)
{
if (*a != *b) { //2つの数が等しくなければ交換します
int buf = *a; //ここで変数bufを宣言
*a = *b;
*b = buf;
}
return;
}
今日の名言
度胸が欲しければ、恐ろしくて手が出ないことに挑んでみることだ。これを欠かさず
やり続けて成功の実績を作るのだ。
これが恐怖心を克服するための、もっとも迅速でしかも確実な方法である。
デール・カーネギー
自分を激励する秘訣は、自分に向かってこう言い聞かせることだ。「自分と大して
知能の違わない、普通のできの人間でさえ、難問題を解決して者が数えきれない
ほどいるのに、自分にできないことがあるものか」
ウィリアム・フェザー
我々は決して降伏もしなければ敗北もしない。最後の最後まで戦い抜くつもりだ。
我々はフランスで戦うし海上でも戦う。ますます自信を固めて空中でも戦い抜くのだ。
どんなに犠牲が大きかろうと、我々はこの国を守りぬくのだ。海岸で、上陸地点で、
戦線で、市街地で、山岳地で、あらゆる所で戦い抜くのだ。我々は決して降伏しない。
そして、たとえ-私は一瞬たりともそんなことを信じないのだが-この全イギリス本土
あるいは大部分が敵の手に落ち、国民が飢えに苦しむようなことがあっても、我々は
海外の我が大英帝国の領土において我がイギリス戦隊に護衛されつつ、戦闘を続ける
だろう。 そしてついには、神の御心にかなった日に、海の彼方の新世界(アメリカ)が
その全軍事力と全軍隊を投じて、この旧世界を救い出し、解放するためにやってくるだろう。
ウインストン・チーチャル
使う前なら、どこでも自由に宣言できるのです。
それでは、変数を宣言する位置ついて詳しく見て行きましょう。
今、2つの変数の値を交換する関数を例に、変数を宣言する位置を見てみましょう。
void SwapFunction(int *a, inb *b)
{
if (*a == *b) {
return;
}
int buf = *a; //ここで変数bufを宣言しています
*a = *b;
*b = buf;
return;
}
変数bufはSwapFunction()関数のブロックの途中で宣言されています。
そして、宣言と同時に初期化もしています。
変数宣言は使う直前がオススメです
変数の宣言は、使う直前にするようにしましょう。
そうでないと宣言が無駄になることもありますし、読みやすさに違いが出てきます。
では、試しにSwapFunction()関数のはじめで変数bufを宣言してみます。
void SwapFunction(int *a, int *b)
{
int buf; //ここで変数bufを宣言しています
if (*a == *b) {
return; //*a == *b なら何もせずに、returnします
}
buf = *a; //ここは *a == *b の時には実行されません
*a = *b;
*b = buf;
return;
}
使わないかもしれない変数をあらかじめ宣言しておくのは、無駄になってしまいます。(^_^;)
どうでしょうか、使う直前に宣言したほうが見やすくありませんか?
しかし、この場合途中リターンが見た目気持ち悪いという方もいるかもしれません。(^_^;)
もっとスマートに書くならこんな感じでしょうか?
お好みでどうぞ^^
こんなサンプルプログラムでも洗練させてみるのも面白いものですよ。
void SwapFunctionPart2(int *a, int *b)
{
if (*a != *b) { //2つの数が等しくなければ交換します
int buf = *a; //ここで変数bufを宣言
*a = *b;
*b = buf;
}
return;
}
今日の名言
度胸が欲しければ、恐ろしくて手が出ないことに挑んでみることだ。これを欠かさず
やり続けて成功の実績を作るのだ。
これが恐怖心を克服するための、もっとも迅速でしかも確実な方法である。
デール・カーネギー
自分を激励する秘訣は、自分に向かってこう言い聞かせることだ。「自分と大して
知能の違わない、普通のできの人間でさえ、難問題を解決して者が数えきれない
ほどいるのに、自分にできないことがあるものか」
ウィリアム・フェザー
我々は決して降伏もしなければ敗北もしない。最後の最後まで戦い抜くつもりだ。
我々はフランスで戦うし海上でも戦う。ますます自信を固めて空中でも戦い抜くのだ。
どんなに犠牲が大きかろうと、我々はこの国を守りぬくのだ。海岸で、上陸地点で、
戦線で、市街地で、山岳地で、あらゆる所で戦い抜くのだ。我々は決して降伏しない。
そして、たとえ-私は一瞬たりともそんなことを信じないのだが-この全イギリス本土
あるいは大部分が敵の手に落ち、国民が飢えに苦しむようなことがあっても、我々は
海外の我が大英帝国の領土において我がイギリス戦隊に護衛されつつ、戦闘を続ける
だろう。 そしてついには、神の御心にかなった日に、海の彼方の新世界(アメリカ)が
その全軍事力と全軍隊を投じて、この旧世界を救い出し、解放するためにやってくるだろう。
ウインストン・チーチャル
関数プロトタイプ宣言
プロトタイプ宣言とは、関数の処理内容を定義する前に、関数の呼び出し方法をあらかじめ
記述しておくことです。C++では、関数呼び出しの前に関数の定義がない場合に必ず
プロトタイプ宣言をしなければなりません。
OKパターン
ソースコードが関数の定義⇛関数呼び出しの順に記述
NGパターン
ソースコードが関数呼び出し⇛関数の定義の順に記述
しかしプロトタイプ宣言を書けばOKに
プロトタイプ宣言⇛関数呼び出し⇛関数の定義
具体的にはこのようになります。^^
プロトタイプ宣言があれば、ソースコードが見やすくなりますね(^^)
:
int AddNumber(int, int); //プロトタイプ宣言
int main(void)
{
int a = AddNumber(5, 10); //関数呼び出し
return 0;
}
int AddNumber(int number1, int number2) //関数の定義
{
return number1 + number2;
}
:
Cのプロトタイプ宣言と違うところ
Cでは「不明な関数は int型を返す」という暗黙のルールがありました。
そのためプロトタイプ宣言がなくてもコンパイルエラーにならない場合もあります。
しかしC++では不明な関数があると必ずコンパイルエラーです。厳しいですね(^_^;)
//プロトタイプ宣言なし
int main(void)
{
int a = AddNumber(5, 10); //関数呼び出し
return 0;
}
int AddNumber(int number1, int number2) //関数の定義
{
return number1 + number2;
}
上記プログラムではエラーメッセージが出ましたの例
test.cpp: In function ‘int main()’:
test.cpp:7:28: error: ‘AddNumber’ was not declared in this scope
変数名を含めた関数プロトタイプ宣言
ちなみに、引数を記述するところは型だけでなく変数名も一緒に記述できます。
変数名がある方が、引数の意味が分かりやすいので記述することをオススメします(^^)
//関数の定義の部分をそのままプロトタイプ宣言に使用する例
:
int AddNumber(int number1, int number2);
int main(void)
{
int a = AddNumber(5, 10);
return 0;
}
int AddNumber(int number1, int number2)
{
:
注意
プロトタイプ宣言をしていないCのプログラムをC++でコンパイルする場合は
プロトタイプ宣言を追加してくださいね。
そもそも混ぜて使うなという話もありますが、つまらない所でハマります(^_^;)
今日の名言
ほんの少しばかり勇気に欠けていたために、多くの才能ある人々が一生功を成すことなく
終わっている。思い切って着手する勇気がなかったために一生無名に終わった、大勢の人間が
毎日墓場へ送られる。こうした人々も実行に取り掛かる決断さえついていれば、おそらく名声を
上げていただろう。もし人に認められるようなことを行いたければ、寒さや危険を恐れて、ぼんやりと
立ちすくんでいてはダメだ。思い切って飛び込んで全力を尽くして泳ぎ渡れ!これが冷厳な現実で
ある。絶えず危険を見積もって、小手先の調整ばかりしていてはダメだ。万事大らかだったノアの
大洪水以前なら、150年後の事業のことで友人に相談し、そのせいかを見届けるまで長生きする
ことができたであろう。だがこの忙しい現代では、仕事の着手を手控えて思い迷い、あれやこれやと
人に相談ばかりしていては、いつの間にか60歳を迎え、せっかく兄弟や親類や友人の助言に従おう
としても、もはやその時間はなくなってしまう。
シドニー・スミス
勇気はまさに人間に必要な第一の特質である。
これが備われば、他の特質も自然に備わってくるからだ。
ウィンストン・チーチャル
追い詰められた若者が意を決して、「世間」という暴れん坊のあごひげを引っ張ると、すっぽりと
手の中に抜け落ちることがある。よく見直すと、それは臆病者を追い払うためのつけヒゲなのだ。
ラルフ・ワルド・エマーソン
記述しておくことです。C++では、関数呼び出しの前に関数の定義がない場合に必ず
プロトタイプ宣言をしなければなりません。
OKパターン
ソースコードが関数の定義⇛関数呼び出しの順に記述
NGパターン
ソースコードが関数呼び出し⇛関数の定義の順に記述
しかしプロトタイプ宣言を書けばOKに
プロトタイプ宣言⇛関数呼び出し⇛関数の定義
具体的にはこのようになります。^^
プロトタイプ宣言があれば、ソースコードが見やすくなりますね(^^)
:
int AddNumber(int, int); //プロトタイプ宣言
int main(void)
{
int a = AddNumber(5, 10); //関数呼び出し
return 0;
}
int AddNumber(int number1, int number2) //関数の定義
{
return number1 + number2;
}
:
Cのプロトタイプ宣言と違うところ
Cでは「不明な関数は int型を返す」という暗黙のルールがありました。
そのためプロトタイプ宣言がなくてもコンパイルエラーにならない場合もあります。
しかしC++では不明な関数があると必ずコンパイルエラーです。厳しいですね(^_^;)
//プロトタイプ宣言なし
int main(void)
{
int a = AddNumber(5, 10); //関数呼び出し
return 0;
}
int AddNumber(int number1, int number2) //関数の定義
{
return number1 + number2;
}
上記プログラムではエラーメッセージが出ましたの例
test.cpp: In function ‘int main()’:
test.cpp:7:28: error: ‘AddNumber’ was not declared in this scope
変数名を含めた関数プロトタイプ宣言
ちなみに、引数を記述するところは型だけでなく変数名も一緒に記述できます。
変数名がある方が、引数の意味が分かりやすいので記述することをオススメします(^^)
//関数の定義の部分をそのままプロトタイプ宣言に使用する例
:
int AddNumber(int number1, int number2);
int main(void)
{
int a = AddNumber(5, 10);
return 0;
}
int AddNumber(int number1, int number2)
{
:
注意
プロトタイプ宣言をしていないCのプログラムをC++でコンパイルする場合は
プロトタイプ宣言を追加してくださいね。
そもそも混ぜて使うなという話もありますが、つまらない所でハマります(^_^;)
今日の名言
ほんの少しばかり勇気に欠けていたために、多くの才能ある人々が一生功を成すことなく
終わっている。思い切って着手する勇気がなかったために一生無名に終わった、大勢の人間が
毎日墓場へ送られる。こうした人々も実行に取り掛かる決断さえついていれば、おそらく名声を
上げていただろう。もし人に認められるようなことを行いたければ、寒さや危険を恐れて、ぼんやりと
立ちすくんでいてはダメだ。思い切って飛び込んで全力を尽くして泳ぎ渡れ!これが冷厳な現実で
ある。絶えず危険を見積もって、小手先の調整ばかりしていてはダメだ。万事大らかだったノアの
大洪水以前なら、150年後の事業のことで友人に相談し、そのせいかを見届けるまで長生きする
ことができたであろう。だがこの忙しい現代では、仕事の着手を手控えて思い迷い、あれやこれやと
人に相談ばかりしていては、いつの間にか60歳を迎え、せっかく兄弟や親類や友人の助言に従おう
としても、もはやその時間はなくなってしまう。
シドニー・スミス
勇気はまさに人間に必要な第一の特質である。
これが備われば、他の特質も自然に備わってくるからだ。
ウィンストン・チーチャル
追い詰められた若者が意を決して、「世間」という暴れん坊のあごひげを引っ張ると、すっぽりと
手の中に抜け落ちることがある。よく見直すと、それは臆病者を追い払うためのつけヒゲなのだ。
ラルフ・ワルド・エマーソン
2013年8月10日土曜日
コメントスタイル
C++でのコメントスタイルを紹介します。
コメントはプログラムのコンパイルや実行には影響しません。
分かりやすいプログラムを記述するために、適宜活用していきたいですね^^
コメントの記述例
前回、コメントを書くときに //(スラッシュ2つ)を使えるようになったと書きました。
PeachBoxクラスで追加したデストラクタをコメントにしてみましょう。
class {
public:
PeachBox();
//~PeachBox();
void AddPeach(int n);
:
//PeachBox::~PeachBox()
//{
// cout << "桃の桐箱オブジェクトを終了します^^" << endl;
//}
:
このように書くと、// から行の終わりまでがコメントになります。
コメントはソースファイルに説明文を記載するときや、処理の一部を一時的に反映させないように
するときに使います。
コメントは、行のどこに書いても構いませんが、" "(ダブルクォーテーション)間の文字列内では
無効になりますので注意してください。
Which one is better? /* */ or //
Cのコメントで使用していた /* */ はC++でも使えます。しかし、コメントを書くときは // を
使うほうが断然オススメです。次の例を見てください。
//を使用
:
//PeachBox::~PeachBox()
//{
// cout << "桃の桐箱オブジェクトを終了します^^" << endl;
//}
:
/* */ と // を使用
:
/*
PeachBox::~PeachBox()
{
// 出力
cout << "桃の桐箱オブジェクトを終了します^^" << endl;
}
*/
:
/* */ を使用
:
/*PeachBox::~PeachBox()
{
/* 出力 */←コメントはここまで
cout << "桃の桐箱オブジェクトを終了します^^" << endl;
}
*/←ココは??
:
このように、/* と */ で囲むと、コメントが途中までになってしまうことがあります。
気づかなければコンパイルエラーになってしまいますね。(^_^;)
また、コメントを終わりたいときに */ をタイプするのって結構面倒に感じませんか?
余計なところに頭を悩ませず、便利なコトはどんどん取り入れ手間を省く。
こうして空き時間を増やせば、また新しいことにチャレンジできるようになります。
ビジネスの重要なマインドの一つですね(^^)
今日の名言
機会を逃すな!人生はすべて機械である。一番先頭を行く者は、やる気があり、思い切って
実行する人間である。「安全第一」を守っていては、あまり遠くへボードを漕ぎ出せない。
デール・カーネギー
我々は「この世」しか知らないが、「この世」はさらに大きな世界の一部であるかもしれない。
そうした世界が存在すると信じることは、この世で生を受けた者が果たすべき、最も大きな
役割であると言えるだろう。「科学的」生活そのものは、「おそらく」という考えに大いに関係ある。
そして総体に言って、人生の全てはこの「おそらく」によって決定される。「おそらく」を抜きにしては
闘っても勝利は得られず、誠実な行為も勇気ある行為も行えない。せっかく人に尽くしても、寛大に
振舞っても、また科学的探索を行なっても、教科書を作っても、誤りを犯しかねない。我々がこうして
生きていられるのも、結局は絶えず危険を冒してはそれを征服するからである。
「必ず実現させる」という強い信念だけが、こうした本来実現するかどうかわからない結果を
実現させるのである。
ウィリアム・ジェイムズ
たとえ信念があっても、達成できることはごく僅かなものだ。
しかし、信念がなければ何事も達成できない。
サミュエル・バトラー
コメントはプログラムのコンパイルや実行には影響しません。
分かりやすいプログラムを記述するために、適宜活用していきたいですね^^
コメントの記述例
前回、コメントを書くときに //(スラッシュ2つ)を使えるようになったと書きました。
PeachBoxクラスで追加したデストラクタをコメントにしてみましょう。
class {
public:
PeachBox();
//~PeachBox();
void AddPeach(int n);
:
//PeachBox::~PeachBox()
//{
// cout << "桃の桐箱オブジェクトを終了します^^" << endl;
//}
:
このように書くと、// から行の終わりまでがコメントになります。
コメントはソースファイルに説明文を記載するときや、処理の一部を一時的に反映させないように
するときに使います。
コメントは、行のどこに書いても構いませんが、" "(ダブルクォーテーション)間の文字列内では
無効になりますので注意してください。
Which one is better? /* */ or //
Cのコメントで使用していた /* */ はC++でも使えます。しかし、コメントを書くときは // を
使うほうが断然オススメです。次の例を見てください。
//を使用
:
//PeachBox::~PeachBox()
//{
// cout << "桃の桐箱オブジェクトを終了します^^" << endl;
//}
:
/* */ と // を使用
:
/*
PeachBox::~PeachBox()
{
// 出力
cout << "桃の桐箱オブジェクトを終了します^^" << endl;
}
*/
:
/* */ を使用
:
/*PeachBox::~PeachBox()
{
/* 出力 */←コメントはここまで
cout << "桃の桐箱オブジェクトを終了します^^" << endl;
}
*/←ココは??
:
このように、/* と */ で囲むと、コメントが途中までになってしまうことがあります。
気づかなければコンパイルエラーになってしまいますね。(^_^;)
また、コメントを終わりたいときに */ をタイプするのって結構面倒に感じませんか?
余計なところに頭を悩ませず、便利なコトはどんどん取り入れ手間を省く。
こうして空き時間を増やせば、また新しいことにチャレンジできるようになります。
ビジネスの重要なマインドの一つですね(^^)
今日の名言
機会を逃すな!人生はすべて機械である。一番先頭を行く者は、やる気があり、思い切って
実行する人間である。「安全第一」を守っていては、あまり遠くへボードを漕ぎ出せない。
デール・カーネギー
我々は「この世」しか知らないが、「この世」はさらに大きな世界の一部であるかもしれない。
そうした世界が存在すると信じることは、この世で生を受けた者が果たすべき、最も大きな
役割であると言えるだろう。「科学的」生活そのものは、「おそらく」という考えに大いに関係ある。
そして総体に言って、人生の全てはこの「おそらく」によって決定される。「おそらく」を抜きにしては
闘っても勝利は得られず、誠実な行為も勇気ある行為も行えない。せっかく人に尽くしても、寛大に
振舞っても、また科学的探索を行なっても、教科書を作っても、誤りを犯しかねない。我々がこうして
生きていられるのも、結局は絶えず危険を冒してはそれを征服するからである。
「必ず実現させる」という強い信念だけが、こうした本来実現するかどうかわからない結果を
実現させるのである。
ウィリアム・ジェイムズ
たとえ信念があっても、達成できることはごく僅かなものだ。
しかし、信念がなければ何事も達成できない。
サミュエル・バトラー
2013年8月8日木曜日
CとC++で違うところを少々
なんだかC++の話が多めですね、まぁ時代はオブジェクト指向ということで^^
今日はコラム的な話になるので、さらっと読んでみてください。
C++ではCと比べてクラスやオブジェクト以外に様々な機能が拡張されています。
今後も少しずつ紹介していきますので、ぜひ身に付けて入ってください。
人は、日ごろから余程意識しない限り、段々と物事を忘れていってしまいます。
自分で書いたプログラムでも、週末を挟んで月曜になれば、あれっ?何てこともあります(^_^;)
ましてや一ヶ月先、半年も経てば、大分記憶の彼方に飛ばされていってしまうものです。
説明する必要に迫られても思い出すのは至難の技です。
そんなときの助けになるのがコメントです。
どういう意図でその処理にしているのか、ちょっとした説明があるだけで可読性がかなり違います。
また、「今は仕様が未確定で仮実装になっているので、後で直す目印にする」などにも使えます。
コメントの書き方は、Cではコメントにしたい部分を /* と */ で囲みました。
C++では コメントしたい先頭行に //(スラッシュ2つ) を使う方法も追加されています。
もっとも最近のコンパイラでは C でも // が使えたりします。
ちょっとコメントにするときにすごく便利ですね^^
過度のコメントは考えものですが、品質を意識する上では必要不可欠だと思います。
あと、関数プロトタイプ宣言が厳しくなりました。C++では、関数定義の前に関数呼び出しがある
場合に、必ずプロトタイプ宣言をしておかないとコンパイルエラーになってしまいます。
これについてはC, C++どちらでもプロトタイプ宣言はしっかり書くということにしておけば
特に問題ないでしょう。
そして、スゴイところとして取り上げるのが、変数宣言はどこででもできるようになったことです。
Cではローカル変数の宣言を関数の先頭で行っていました。変数宣言を{ } で囲んだブロックの
先頭で行う必要がありました。C++では変数宣言の自由度が高くなり、使う前ならブロック内の
どこでも変数宣言が可能になりました。
どこでも可ということは、使う直前に宣言できるということです。Cでは変数が必要になると関数の
先頭まで戻らないといけませんが、いざ使う場所にスクロールして戻ってくると、あれれっ?という
なんとびっくり、忘れた!なんてことにもなります(-_-;)
こうした無駄な作業も、積もり積もってアウトプットに影響がでてきます。
作業効率もよくなるし、読みやすくなるなら、便利な機能はどんどん使っていきたいですね^^
そして最後に、C++では定数を宣言するときの const がパワーアップしています。
次回以降でみていきますが、C++ではアクセス制限をより強く意識しているため
const が随所に出てきます。constを使いこなして良いプログラムが書けるようになりましょう^^
今日の名言
もし、からし種一粒ほどの信仰があるなら、この山に向かって「ここからあそこに移れ」と言えば、
移るであろう。このように、あなたにできないことは何もないであろう。
「マタイによる福音書」第17章
最大の名誉は決して倒れないことではない。倒れるたびに起き上がることである。
孔子
目標をあくまで貫くことは、気概あるものの精神をがっちりと支える筋金の一本であり、成功の
最大の条件である。これがなければ、いかなる天才でも方針を失い、ただやたらにエネルギーを
浪費するだけである。
チェスターフィールド卿
今日はコラム的な話になるので、さらっと読んでみてください。
C++ではCと比べてクラスやオブジェクト以外に様々な機能が拡張されています。
今後も少しずつ紹介していきますので、ぜひ身に付けて入ってください。
人は、日ごろから余程意識しない限り、段々と物事を忘れていってしまいます。
自分で書いたプログラムでも、週末を挟んで月曜になれば、あれっ?何てこともあります(^_^;)
ましてや一ヶ月先、半年も経てば、大分記憶の彼方に飛ばされていってしまうものです。
説明する必要に迫られても思い出すのは至難の技です。
そんなときの助けになるのがコメントです。
どういう意図でその処理にしているのか、ちょっとした説明があるだけで可読性がかなり違います。
また、「今は仕様が未確定で仮実装になっているので、後で直す目印にする」などにも使えます。
コメントの書き方は、Cではコメントにしたい部分を /* と */ で囲みました。
C++では コメントしたい先頭行に //(スラッシュ2つ) を使う方法も追加されています。
もっとも最近のコンパイラでは C でも // が使えたりします。
ちょっとコメントにするときにすごく便利ですね^^
過度のコメントは考えものですが、品質を意識する上では必要不可欠だと思います。
あと、関数プロトタイプ宣言が厳しくなりました。C++では、関数定義の前に関数呼び出しがある
場合に、必ずプロトタイプ宣言をしておかないとコンパイルエラーになってしまいます。
これについてはC, C++どちらでもプロトタイプ宣言はしっかり書くということにしておけば
特に問題ないでしょう。
そして、スゴイところとして取り上げるのが、変数宣言はどこででもできるようになったことです。
Cではローカル変数の宣言を関数の先頭で行っていました。変数宣言を{ } で囲んだブロックの
先頭で行う必要がありました。C++では変数宣言の自由度が高くなり、使う前ならブロック内の
どこでも変数宣言が可能になりました。
どこでも可ということは、使う直前に宣言できるということです。Cでは変数が必要になると関数の
先頭まで戻らないといけませんが、いざ使う場所にスクロールして戻ってくると、あれれっ?という
なんとびっくり、忘れた!なんてことにもなります(-_-;)
こうした無駄な作業も、積もり積もってアウトプットに影響がでてきます。
作業効率もよくなるし、読みやすくなるなら、便利な機能はどんどん使っていきたいですね^^
そして最後に、C++では定数を宣言するときの const がパワーアップしています。
次回以降でみていきますが、C++ではアクセス制限をより強く意識しているため
const が随所に出てきます。constを使いこなして良いプログラムが書けるようになりましょう^^
今日の名言
もし、からし種一粒ほどの信仰があるなら、この山に向かって「ここからあそこに移れ」と言えば、
移るであろう。このように、あなたにできないことは何もないであろう。
「マタイによる福音書」第17章
最大の名誉は決して倒れないことではない。倒れるたびに起き上がることである。
孔子
目標をあくまで貫くことは、気概あるものの精神をがっちりと支える筋金の一本であり、成功の
最大の条件である。これがなければ、いかなる天才でも方針を失い、ただやたらにエネルギーを
浪費するだけである。
チェスターフィールド卿
2013年8月7日水曜日
C++メンバ関数の良いところ
今回はメンバ関数と使うと何が便利になるのかを説明します。^^
メンバ関数を使う最大のメリットとは、メンバ変数へのアクセスを制限できることなのです。
次の例を見てください。
桃の桐箱クラス
class PeachBox {
public:
void Add(int addpeach);
void Del(int delpeach);
void Empty();
int GetTotal();
private:
int m_total;
};
PeachBoxクラスでは、メンバ変数 m_total がprivateなので、直接値を設定することができません。
値を設定するためには、メンバ関数を使うようにします。
:
int main(void)
{
PeachBox myPeachBox;
myPeachBox.m_total = 5; //これはコンパイルエラーになります(^_^;)
:
C言語の構造体には、アクセス制限の仕組みはありませんでした。
そのため意図しない箇所で、うっかりメンバ変数に直接アクセスしてもエラーにはなりません。
つまり予定外に値が変更されるのを完全に防ぐことはできないのです。
アクセス制限があれば、安全なプログラムを作成することができます。^^
また、メンバ関数での値チェックができます。
メンバ関数でメンバ変数の値を設定することで、設定値が正しいかどうかをチェックできます。
チェック機能を追加した例を見てください。
void PeachBox::Add(int addpeach)
{
m_total += addpeach;
if (m_total > 18) { //18個を超えるときは、18個に設定する
m_total = 18; //桐箱は18個入りと決めた^^
}
return;
}
メンバ関数にチェック機能を付けておくことで、無効なデータをガードし、
また一歩安全なプログラムに近づきます。
また、メンバ変数の設定処理が1つだけなので、将来の修正も容易になります。
例えば、PeachBoxクラスでの管理が桃の数ではなく、重量に変更になったとします。
もし直接値を入力している場合は、修正するのも大変です(^_^;)
数が少なければいいかもしれませんが、何箇所にもわたって設定箇所があった場合は、
どうしても漏れや間違いが生じるものです。
仮に修正し忘れがあったとしても、コンパイルエラーにはなりませんので間違いには
気づかないままになってしまうでしょう。
そんなことを考えながら一つ一つ直していくのは、頭の痛い作業です。
そしてまた、余計なミスにも繋がります。
個数管理から重量管理への変更1 大変だ(-_-;)
: :
PeachBox myPeachBox; PeachBox myPeachBox;
myPeachBox.m_total = 6; myPeachBox.m_total = 180;
: :
myPeachBox.m_total = 12; ⇒ myPeachBox.m_total = 200;
: :
myPeachBox.m_total = 18; myPeachBox.m_total = 190;
: :
これが、メンバ関数を使用している場合は、修正箇所も少なく簡単です。
個数管理から重量管理への変更2 お手軽だ(^^)v
void PeachBox::Add(int addpeach) void PeachBox::Add(int addpeach)
{ {
m_total += addpeach: m_total += addpeach * 150; //1個150g換算
} }
void PeachBox::Del(int delpeach) ⇒ void PeachBox::Del(int delpeach)
{ {
m_total -= delpeach; m_total -= delpeach * 150; //1個150g換算
} }
このようにメンバ関数をうまく使えば、仕様変更にも間単に対応できますね^^
今日の名言
「不可能」と言う文字は、愚か者の辞書にしか存在しない。
ナポレオン
恐ろしくてできそうもないことを成し遂げれば、恐怖は必ず消滅する。
ラルフ・ワルド・エマーソン
この世を動かす力は希望である。やがて成長して新しい種が得られると言う希望がなければ、
農民は畑に種をまかない。子どもが生まれると言う希望がなければ、若者は結婚できない。
利益が得られると言う希望がなければ、商人は商売に取り掛からない。
マルティン・ルター
メンバ関数を使う最大のメリットとは、メンバ変数へのアクセスを制限できることなのです。
次の例を見てください。
桃の桐箱クラス
class PeachBox {
public:
void Add(int addpeach);
void Del(int delpeach);
void Empty();
int GetTotal();
private:
int m_total;
};
PeachBoxクラスでは、メンバ変数 m_total がprivateなので、直接値を設定することができません。
値を設定するためには、メンバ関数を使うようにします。
:
int main(void)
{
PeachBox myPeachBox;
myPeachBox.m_total = 5; //これはコンパイルエラーになります(^_^;)
:
C言語の構造体には、アクセス制限の仕組みはありませんでした。
そのため意図しない箇所で、うっかりメンバ変数に直接アクセスしてもエラーにはなりません。
つまり予定外に値が変更されるのを完全に防ぐことはできないのです。
アクセス制限があれば、安全なプログラムを作成することができます。^^
また、メンバ関数での値チェックができます。
メンバ関数でメンバ変数の値を設定することで、設定値が正しいかどうかをチェックできます。
チェック機能を追加した例を見てください。
void PeachBox::Add(int addpeach)
{
m_total += addpeach;
if (m_total > 18) { //18個を超えるときは、18個に設定する
m_total = 18; //桐箱は18個入りと決めた^^
}
return;
}
メンバ関数にチェック機能を付けておくことで、無効なデータをガードし、
また一歩安全なプログラムに近づきます。
また、メンバ変数の設定処理が1つだけなので、将来の修正も容易になります。
例えば、PeachBoxクラスでの管理が桃の数ではなく、重量に変更になったとします。
もし直接値を入力している場合は、修正するのも大変です(^_^;)
数が少なければいいかもしれませんが、何箇所にもわたって設定箇所があった場合は、
どうしても漏れや間違いが生じるものです。
仮に修正し忘れがあったとしても、コンパイルエラーにはなりませんので間違いには
気づかないままになってしまうでしょう。
そんなことを考えながら一つ一つ直していくのは、頭の痛い作業です。
そしてまた、余計なミスにも繋がります。
個数管理から重量管理への変更1 大変だ(-_-;)
: :
PeachBox myPeachBox; PeachBox myPeachBox;
myPeachBox.m_total = 6; myPeachBox.m_total = 180;
: :
myPeachBox.m_total = 12; ⇒ myPeachBox.m_total = 200;
: :
myPeachBox.m_total = 18; myPeachBox.m_total = 190;
: :
これが、メンバ関数を使用している場合は、修正箇所も少なく簡単です。
個数管理から重量管理への変更2 お手軽だ(^^)v
void PeachBox::Add(int addpeach) void PeachBox::Add(int addpeach)
{ {
m_total += addpeach: m_total += addpeach * 150; //1個150g換算
} }
void PeachBox::Del(int delpeach) ⇒ void PeachBox::Del(int delpeach)
{ {
m_total -= delpeach; m_total -= delpeach * 150; //1個150g換算
} }
このようにメンバ関数をうまく使えば、仕様変更にも間単に対応できますね^^
今日の名言
「不可能」と言う文字は、愚か者の辞書にしか存在しない。
ナポレオン
恐ろしくてできそうもないことを成し遂げれば、恐怖は必ず消滅する。
ラルフ・ワルド・エマーソン
この世を動かす力は希望である。やがて成長して新しい種が得られると言う希望がなければ、
農民は畑に種をまかない。子どもが生まれると言う希望がなければ、若者は結婚できない。
利益が得られると言う希望がなければ、商人は商売に取り掛からない。
マルティン・ルター
2013年8月6日火曜日
コンストラクタとデストラクタ
コンストラクタとは、オブジェクトを生成するときに必ず呼び出される関数です。
主な役割が、メンバ変数の初期化を行うことです。
以前取り上げたPeachBoxクラスでは、これまでEmpty()関数でモモの箱を空にして
(桃の数を0に初期化)してから、Add()関数で桃を追加していました。
:
int main(void)
{
PeachBox myPeachBox; //オブジェクトを生成、すなわちmyPeachBoxがインスタンス化
myPeachBox.Empty(); //初期化 桃の数を0にする
myPeachBox.Add(12); //桃を1ダース追加
:
return 0;
}
このようにEmpty()関数を先に呼べば安全なのですが、Empty()関数を呼ばずにAdd()関数を
呼び出すと、桃の数を表すメンバ変数m_totalが初期化されてない状態で値を加えることになります。
変数はキチンと宣言しただけでは、不定値が入っています。たまたま0かもしれませんし、そうではないかもしれません。これは予想のできない動作を招くおそれがあります。
コンストラクタの定義
コンストラクタは、オブジェクトの生成時に自動的に呼び出される特殊な関数です。
コンストラクタは、アクセス指定子をpublicにして記述します。privateにしたり、アクセス指定子を
省略するとコンパイルエラーになりますので注意してください。
class PeachBox{
public:
PeachBox(); //コンストラクタの宣言です^^ 必ずクラス名と同じ名前になります
:
};
PeachBox::PeachBox() //コンストラクタの処理を定義します
{
m_total = 0; //メンバ変数を初期化しています
}
:
int main(void)
{
PeachBox myPeachBox; //ここでコンストラクタが呼び出される
:
}
コンストラクタには戻り値がなく、型も指定しないことに注意してください。
このように、コンストラクタでメンバ変数の値を初期化することで、さきほどの様にメンバ変数が
不定値のまま使用することで、予期せぬ結果になるという事態を防ぐことができます。
なお、コンストラクタは引数なしのもの、引数ありのもの、のように複数定義できます。
具体的な使い方は次回以降で見ていくこととします^^
もし、コンストラクタで行う処理が何もなければコンストラクタは記述しなくてもかまいません。
その場合でも、内部的には自動でコンストラクタを生成し呼び出しているのです(^^)v
次に、デストラクタについて見ていきます。
こちらは、オブジェクトが消滅する時に呼ばれる関数です。
主な役割は、プログラムの後始末を行うことです。
デストラクタもアクセス指定子はpublicにします。privateにしたりアクセス指定子を省略すると
コンパイルエラーになりますのでご注意を(^_^;)
class PeachBox {
public:
PeachBox();
~PeachBox(); //デストラクタの宣言です。 クラス名と同じ名前で先頭に~(チルダ)が付きます。
:
};
:
PeachBox::~PeachBox() //デストラクタの定義です。 ここではプログラム終了を表示しています。
{
std::cout << "桃の化粧箱オブジェクトが終了します。" << std::endl;
}
:
int main(void)
{
PeachBox myPeachBox();
myPeachBox.Add(12);
std::cout << "化粧箱の中の桃の数は" << myPeachBox.GetTotal() << "個です。" << std::endl;
return 0;
} //オブジェクトの有効範囲はここまで
デストラクタはオブジェクトの有効範囲が終わった時に呼び出されます。
上記の場合は、return 0 でmain()関数が終了した後になります。
実行例
root# ./peach
化粧箱の中の桃の数は12個です。
桃の化粧箱オブジェクトが終了します。
便利なデストラクタの使い方
プログラムの後始末ですので、メンバ関数内で動的にメモリを確保した場合に、デストラクタで
解放するようにしておくと、メモリ解放漏れがなくなり安心です。
デストラクタの特徴
コンストラクタ同様、デストラクタにも戻り値がなく、型も指定しません。
また引数をもてず、クラスの中に一つだけしか定義できません。
デストラクタも必要な処理が何もなければ、定義する必要はありません。
その場合でも、内部的には自動でデストラクタを生成し、呼び出しています。
今日の名言
自然に振る舞う態度ほど、身につけやすいものはない。ただ自分のことを忘れさえすればよい。
「こういうふうに見て欲しい」という気持ちを忘れさえすればよい。
デール・カーネギー
家から出るときは、いつでもあごを引いて頭をまっすぐに立て、できる限り大きく呼吸をすること。
日光を吸い込むのだ。友人には笑顔をもって接し、握手には心をこめる。誤解される心配などせず、
敵のことに心を煩わさない。やりたいことをしっかりと心の中で決める。そして、まっしぐらに目標に
向かって突進する。大きな素晴らしいことをやり遂げたいと考えそれを絶えず念頭に置く。すると、
月日の経つにしたがって、いつの間にか念願を達成するのに必要な機会が自分の手の中に
握られていることに気がつくだろう。あたかも珊瑚虫が潮流から養分を摂取するようなものである。
また、有能で、真面目で、他人の役に立つ人物になることを心がけ、それを常に忘れないでいる。
すると、日の経つにしたがって、その様な人物になっていく。-心の働きは絶妙なものである。
正しい精神状態、すなわち勇気、率直、明朗さを常に持ち続けること。正しい精神状態は優れた
創造力を備えている。全ての物事は願望から生まれ、心からの願いは全てかなえられる。
人間は、心がけたとおりになるものである。あごを引いて頭をまっすぐに立てよう。
神となるための前段階-それが人間なのだ。
エルバート・ハバート
主な役割が、メンバ変数の初期化を行うことです。
以前取り上げたPeachBoxクラスでは、これまでEmpty()関数でモモの箱を空にして
(桃の数を0に初期化)してから、Add()関数で桃を追加していました。
:
int main(void)
{
PeachBox myPeachBox; //オブジェクトを生成、すなわちmyPeachBoxがインスタンス化
myPeachBox.Empty(); //初期化 桃の数を0にする
myPeachBox.Add(12); //桃を1ダース追加
:
return 0;
}
このようにEmpty()関数を先に呼べば安全なのですが、Empty()関数を呼ばずにAdd()関数を
呼び出すと、桃の数を表すメンバ変数m_totalが初期化されてない状態で値を加えることになります。
変数はキチンと宣言しただけでは、不定値が入っています。たまたま0かもしれませんし、そうではないかもしれません。これは予想のできない動作を招くおそれがあります。
コンストラクタの定義
コンストラクタは、オブジェクトの生成時に自動的に呼び出される特殊な関数です。
コンストラクタは、アクセス指定子をpublicにして記述します。privateにしたり、アクセス指定子を
省略するとコンパイルエラーになりますので注意してください。
class PeachBox{
public:
PeachBox(); //コンストラクタの宣言です^^ 必ずクラス名と同じ名前になります
:
};
PeachBox::PeachBox() //コンストラクタの処理を定義します
{
m_total = 0; //メンバ変数を初期化しています
}
:
int main(void)
{
PeachBox myPeachBox; //ここでコンストラクタが呼び出される
:
}
コンストラクタには戻り値がなく、型も指定しないことに注意してください。
このように、コンストラクタでメンバ変数の値を初期化することで、さきほどの様にメンバ変数が
不定値のまま使用することで、予期せぬ結果になるという事態を防ぐことができます。
なお、コンストラクタは引数なしのもの、引数ありのもの、のように複数定義できます。
具体的な使い方は次回以降で見ていくこととします^^
もし、コンストラクタで行う処理が何もなければコンストラクタは記述しなくてもかまいません。
その場合でも、内部的には自動でコンストラクタを生成し呼び出しているのです(^^)v
次に、デストラクタについて見ていきます。
こちらは、オブジェクトが消滅する時に呼ばれる関数です。
主な役割は、プログラムの後始末を行うことです。
デストラクタもアクセス指定子はpublicにします。privateにしたりアクセス指定子を省略すると
コンパイルエラーになりますのでご注意を(^_^;)
class PeachBox {
public:
PeachBox();
~PeachBox(); //デストラクタの宣言です。 クラス名と同じ名前で先頭に~(チルダ)が付きます。
:
};
:
PeachBox::~PeachBox() //デストラクタの定義です。 ここではプログラム終了を表示しています。
{
std::cout << "桃の化粧箱オブジェクトが終了します。" << std::endl;
}
:
int main(void)
{
PeachBox myPeachBox();
myPeachBox.Add(12);
std::cout << "化粧箱の中の桃の数は" << myPeachBox.GetTotal() << "個です。" << std::endl;
return 0;
} //オブジェクトの有効範囲はここまで
デストラクタはオブジェクトの有効範囲が終わった時に呼び出されます。
上記の場合は、return 0 でmain()関数が終了した後になります。
実行例
root# ./peach
化粧箱の中の桃の数は12個です。
桃の化粧箱オブジェクトが終了します。
便利なデストラクタの使い方
プログラムの後始末ですので、メンバ関数内で動的にメモリを確保した場合に、デストラクタで
解放するようにしておくと、メモリ解放漏れがなくなり安心です。
デストラクタの特徴
コンストラクタ同様、デストラクタにも戻り値がなく、型も指定しません。
また引数をもてず、クラスの中に一つだけしか定義できません。
デストラクタも必要な処理が何もなければ、定義する必要はありません。
その場合でも、内部的には自動でデストラクタを生成し、呼び出しています。
今日の名言
自然に振る舞う態度ほど、身につけやすいものはない。ただ自分のことを忘れさえすればよい。
「こういうふうに見て欲しい」という気持ちを忘れさえすればよい。
デール・カーネギー
家から出るときは、いつでもあごを引いて頭をまっすぐに立て、できる限り大きく呼吸をすること。
日光を吸い込むのだ。友人には笑顔をもって接し、握手には心をこめる。誤解される心配などせず、
敵のことに心を煩わさない。やりたいことをしっかりと心の中で決める。そして、まっしぐらに目標に
向かって突進する。大きな素晴らしいことをやり遂げたいと考えそれを絶えず念頭に置く。すると、
月日の経つにしたがって、いつの間にか念願を達成するのに必要な機会が自分の手の中に
握られていることに気がつくだろう。あたかも珊瑚虫が潮流から養分を摂取するようなものである。
また、有能で、真面目で、他人の役に立つ人物になることを心がけ、それを常に忘れないでいる。
すると、日の経つにしたがって、その様な人物になっていく。-心の働きは絶妙なものである。
正しい精神状態、すなわち勇気、率直、明朗さを常に持ち続けること。正しい精神状態は優れた
創造力を備えている。全ての物事は願望から生まれ、心からの願いは全てかなえられる。
人間は、心がけたとおりになるものである。あごを引いて頭をまっすぐに立てよう。
神となるための前段階-それが人間なのだ。
エルバート・ハバート
2013年8月4日日曜日
アクセス制御について
以前、クラスの概念の記事でサンプルプログラム内にさらっと仕込んであった
アクセス指定子の説明です。
アクセス制御を使いこなすと他のオブジェクトに対してメンバを
隠蔽したり公開したりすることができます。
学生クラス(再掲)
class Student { //クラス名
public: //キーワード
//メンバ関数 学生情報を設定する
int SetStudentInfo(int num, char *name, int ja, int ma, int sci);
//メンバ関数 学籍番号から3教科の合計点を求める
int GetSum(int student_num);
private: //キーワード
int number; //メンバ変数 学籍番号
char name[20]; //メンバ変数 氏名
int japanese; //メンバ変数 国語
int math; //メンバ変数 数学
int science; //メンバ変数 理科
};
この public, private はアクセス指定子といいます。
アクセス指定子の後には「:(コロン)」が必要です。
アクセス指定子は、メンバへのアクセスを制御するためのラベルなのです。
public
publicメンバは、他のオブジェクトのメンバ関数や普通の関数からアクセスできます。
また、同じオブジェクト内のメンバ関数からもアクセスできます。
private
privateメンバは、他のオブジェクトのメンバ関数や普通の関数からアクセスできません。(^_^;)
同じオブジェクト内のメンバ関数からのみアクセスできます。
あと、アクセス指定子には protected というのがあります。
protectedはそのクラス単独で使うときはprivateと同じ扱いです。
継承を行った時にサブクラスから見るとpublicとして扱えるという違いがあります。
またまた、新しい言葉がしれっと登場していますね。詳しくは別の機会にしましょう。
今今はよく分からなくても全然OKです^^
アクセス指定子の記述
見づらいこと極まりないですが、こんな書き方もできます。
class Student {
public:
int SetStudentInfo(int num, char *name, int ja, int ma, int sci);
private:
int number;
char name[20];
int japanese;
int math;
int science;
public:
int GetSum(int student_num);
};
しかし、このようにバラバラでは可読性が著しく低下しますのでやっぱり一箇所にまとまって
記述するのがいいでしょうね。(^_^;)
また、クラスの中でアクセス指定子を記述しなかった場合はすべてprivateになります。
意図して省略するしているならいいのですが、書き忘れているかもしれませんし、
可読性を考えると、こちらもできれば記述したほうがよいでしょう。
アクセス指定子を全て省略してみました
class Student {
int SetStudentInfo(int num, char *name, int ja, int ma, int sci);
int GetSum(int student_num);
int number;
char name[20];
int japanese;
int math;
int science;
};
とても違和感を覚えます(>_<)
今日の名言
子どもの頃は不器用で体も弱かったので、青年になっても私は神経が落ち着かず、到底勇気を
持てる自信などなかった。私は肉体面だけでなく、精神面でも負けじ魂の面でも、徹底的に
鍛えなおす必要があったのだ。…少年時代の私は、マリアッドの小説の次の一説を繰り返し読んだ
ものだ。小説の主人公に向かって、イギリスの一小戦艦の艦長が、肝っ玉の座った人間になるには
どうすればよいか、教えているくだりである。
「はじめて戦場に出るのは、誰でも恐ろしいものだが、取るべき行動はただひとつ、戦闘など全然
怖くないと言ったかをで立ち向かうことだ。この態度を常にとり続けていると、見せかけでなく、本当に度胸が座ってくる。恐怖を知らぬ態度を繰り返しているうちに、いつの間にか本当に恐怖を感じなく
なり、度胸のある人間になるのだ」
私はこの考えに従って恐怖を克服した。かつては灰色熊から暴れ馬、ガンマンにいたるまで、
ありとあらゆるものが怖かった。しかし怖くないようなふりをしていると、いつか本当に怖くなってきた。
その気になりさえすれば、たいていの物は私と同じ経験をすることができる。
セオドア・ルーズヴェルト
アクセス指定子の説明です。
アクセス制御を使いこなすと他のオブジェクトに対してメンバを
隠蔽したり公開したりすることができます。
学生クラス(再掲)
class Student { //クラス名
public: //キーワード
//メンバ関数 学生情報を設定する
int SetStudentInfo(int num, char *name, int ja, int ma, int sci);
//メンバ関数 学籍番号から3教科の合計点を求める
int GetSum(int student_num);
private: //キーワード
int number; //メンバ変数 学籍番号
char name[20]; //メンバ変数 氏名
int japanese; //メンバ変数 国語
int math; //メンバ変数 数学
int science; //メンバ変数 理科
};
この public, private はアクセス指定子といいます。
アクセス指定子の後には「:(コロン)」が必要です。
アクセス指定子は、メンバへのアクセスを制御するためのラベルなのです。
public
publicメンバは、他のオブジェクトのメンバ関数や普通の関数からアクセスできます。
また、同じオブジェクト内のメンバ関数からもアクセスできます。
private
privateメンバは、他のオブジェクトのメンバ関数や普通の関数からアクセスできません。(^_^;)
同じオブジェクト内のメンバ関数からのみアクセスできます。
あと、アクセス指定子には protected というのがあります。
protectedはそのクラス単独で使うときはprivateと同じ扱いです。
継承を行った時にサブクラスから見るとpublicとして扱えるという違いがあります。
またまた、新しい言葉がしれっと登場していますね。詳しくは別の機会にしましょう。
今今はよく分からなくても全然OKです^^
アクセス指定子の記述
見づらいこと極まりないですが、こんな書き方もできます。
class Student {
public:
int SetStudentInfo(int num, char *name, int ja, int ma, int sci);
private:
int number;
char name[20];
int japanese;
int math;
int science;
public:
int GetSum(int student_num);
};
しかし、このようにバラバラでは可読性が著しく低下しますのでやっぱり一箇所にまとまって
記述するのがいいでしょうね。(^_^;)
また、クラスの中でアクセス指定子を記述しなかった場合はすべてprivateになります。
意図して省略するしているならいいのですが、書き忘れているかもしれませんし、
可読性を考えると、こちらもできれば記述したほうがよいでしょう。
アクセス指定子を全て省略してみました
class Student {
int SetStudentInfo(int num, char *name, int ja, int ma, int sci);
int GetSum(int student_num);
int number;
char name[20];
int japanese;
int math;
int science;
};
とても違和感を覚えます(>_<)
今日の名言
子どもの頃は不器用で体も弱かったので、青年になっても私は神経が落ち着かず、到底勇気を
持てる自信などなかった。私は肉体面だけでなく、精神面でも負けじ魂の面でも、徹底的に
鍛えなおす必要があったのだ。…少年時代の私は、マリアッドの小説の次の一説を繰り返し読んだ
ものだ。小説の主人公に向かって、イギリスの一小戦艦の艦長が、肝っ玉の座った人間になるには
どうすればよいか、教えているくだりである。
「はじめて戦場に出るのは、誰でも恐ろしいものだが、取るべき行動はただひとつ、戦闘など全然
怖くないと言ったかをで立ち向かうことだ。この態度を常にとり続けていると、見せかけでなく、本当に度胸が座ってくる。恐怖を知らぬ態度を繰り返しているうちに、いつの間にか本当に恐怖を感じなく
なり、度胸のある人間になるのだ」
私はこの考えに従って恐怖を克服した。かつては灰色熊から暴れ馬、ガンマンにいたるまで、
ありとあらゆるものが怖かった。しかし怖くないようなふりをしていると、いつか本当に怖くなってきた。
その気になりさえすれば、たいていの物は私と同じ経験をすることができる。
セオドア・ルーズヴェルト
オブジェクトを生成して使ってみる
インスタンス化
クラスからオブジェクトを生成する方法です。定義したクラスはインスタンス化しないと
メモリ領域が確保されませんので、使用できません。
//前回定義した 桃の箱 クラス
class PeachBox {
public:
void Add(int addpeach);
void Del(int delpeach);
void Empty();
int GetTotal();
private:
int m_total;
};
この場合に、桃の箱オブジェクトを生成してみます。
PeachBox myPeachBox; //変数の宣言の仕方と同じですね^^
この myPeachBox がオブジェクトになります。
通常の変数と同様に、好きな名前 がつけられます。
myPeachBoxはPeachBoxクラスのメンバ
Add(), Del(), Empty(), GetTotal(), m_totalを持っています。
また、オブジェクトは複数生成することができます。
PeachBox myPeachBox1;
PeachBox myPeachBox2;
PeachBox myPeachBox3;
:
そして、各オブジェクトごとに別々のデータを格納することができます。
使い方イメージ
myPeachBox1には桃が12個、myPeachBox2には桃が8個あります。
それぞれから2個ずつ取り出し、myPeachBox3に入れます。
このような処理をプログラミングすることになります。^^
メンバ関数の呼び出し
次に、メンバ関数の呼び出し方法を説明します。
同じオブジェクト内のメンバ関数の呼び出し
void PeachBox::Empty()
{
m_total = 0;
}
void PeachBox::Del(int delpeach)
{
m_total -= delpeach;
if (m_total < 0) Empty();
}
同じオブジェクト内のメンバ関数を呼び出すときは、関数名だけの記述でOKです。
ここでは桃の数(m_toal) が 0未満になりそうなときはメンバ関数Empty()を呼び出し
0に設定しています。 桃の数がマイナスだったらおかしいですもんね(^_^;)
他のオブジェクト内のメンバ関数呼び出し
int main()
{
PeachBox myPeachBox1;
PeachBox myPeachBox2;
myPeachBox1.Empty();
myPeachBox2.Add(3);
:
他のオブジェクト内のメンバ関数を呼び出すときは、「.(ピリオド)」を使って
どのオブジェクトのメンバなのかを指定します。
ピリオドを使用するのは、Cの構造体のメンバ参照と同じですね^^
今日の名言
「やろう」と思う強い意志は、これまで行ってきた行動の回数と、そのときの決意の強さによって
決まります。そして行動にかかるたびに、人間の脳は成長します。そうなった時に、本当の信念が
生まれるのです。せっかく決心しても、また美しい気持ちを抱きかけても、実を結ぶことなく立ち消えに
なってしまえば、その損害は機会を失ったときよりはるかに大きいでしょう。その人の将来の目的の
達成が遅れてしまうし、心の冷たい人になってしまうからです。口先だけなら、誰でも強そうなことが
言えます。でも実際にその場で発揮できる勇気は、いつの場合でも十分ではありません。
私たちは、毎日勇気が少しずつ蒸発するに任せているからです。
ヘレン・ケラー
何事にも動じない決断力ほど、気概のある人間を作り出す要因はおそらくあるまい。将来、大人物を
目指す若者や、死後何らかの点で大人物に数えられたいと願う若者は、単に底知れぬ障害を克服
する決心をするだけではダメだ。数知れぬ拒絶と敗北に出会っても、障害を克服してみせる決心が
必要である。
セオドア・ルーズヴェルト
恐怖を克服する決心をしさえすれば、たいていの恐怖は克服できる。恐怖は人の心の中にしか
そんざいしないからだ。
恐ろしくなったら、自分のやるべき仕事のことを一心に考えることだ。すっかり仕事に対する心構えが
できれば、恐怖心は消え去る。
デール・カーネギー
クラスからオブジェクトを生成する方法です。定義したクラスはインスタンス化しないと
メモリ領域が確保されませんので、使用できません。
//前回定義した 桃の箱 クラス
class PeachBox {
public:
void Add(int addpeach);
void Del(int delpeach);
void Empty();
int GetTotal();
private:
int m_total;
};
この場合に、桃の箱オブジェクトを生成してみます。
PeachBox myPeachBox; //変数の宣言の仕方と同じですね^^
この myPeachBox がオブジェクトになります。
通常の変数と同様に、好きな名前 がつけられます。
myPeachBoxはPeachBoxクラスのメンバ
Add(), Del(), Empty(), GetTotal(), m_totalを持っています。
また、オブジェクトは複数生成することができます。
PeachBox myPeachBox1;
PeachBox myPeachBox2;
PeachBox myPeachBox3;
:
そして、各オブジェクトごとに別々のデータを格納することができます。
使い方イメージ
myPeachBox1には桃が12個、myPeachBox2には桃が8個あります。
それぞれから2個ずつ取り出し、myPeachBox3に入れます。
このような処理をプログラミングすることになります。^^
メンバ関数の呼び出し
次に、メンバ関数の呼び出し方法を説明します。
同じオブジェクト内のメンバ関数の呼び出し
void PeachBox::Empty()
{
m_total = 0;
}
void PeachBox::Del(int delpeach)
{
m_total -= delpeach;
if (m_total < 0) Empty();
}
同じオブジェクト内のメンバ関数を呼び出すときは、関数名だけの記述でOKです。
ここでは桃の数(m_toal) が 0未満になりそうなときはメンバ関数Empty()を呼び出し
0に設定しています。 桃の数がマイナスだったらおかしいですもんね(^_^;)
他のオブジェクト内のメンバ関数呼び出し
int main()
{
PeachBox myPeachBox1;
PeachBox myPeachBox2;
myPeachBox1.Empty();
myPeachBox2.Add(3);
:
他のオブジェクト内のメンバ関数を呼び出すときは、「.(ピリオド)」を使って
どのオブジェクトのメンバなのかを指定します。
ピリオドを使用するのは、Cの構造体のメンバ参照と同じですね^^
今日の名言
「やろう」と思う強い意志は、これまで行ってきた行動の回数と、そのときの決意の強さによって
決まります。そして行動にかかるたびに、人間の脳は成長します。そうなった時に、本当の信念が
生まれるのです。せっかく決心しても、また美しい気持ちを抱きかけても、実を結ぶことなく立ち消えに
なってしまえば、その損害は機会を失ったときよりはるかに大きいでしょう。その人の将来の目的の
達成が遅れてしまうし、心の冷たい人になってしまうからです。口先だけなら、誰でも強そうなことが
言えます。でも実際にその場で発揮できる勇気は、いつの場合でも十分ではありません。
私たちは、毎日勇気が少しずつ蒸発するに任せているからです。
ヘレン・ケラー
何事にも動じない決断力ほど、気概のある人間を作り出す要因はおそらくあるまい。将来、大人物を
目指す若者や、死後何らかの点で大人物に数えられたいと願う若者は、単に底知れぬ障害を克服
する決心をするだけではダメだ。数知れぬ拒絶と敗北に出会っても、障害を克服してみせる決心が
必要である。
セオドア・ルーズヴェルト
恐怖を克服する決心をしさえすれば、たいていの恐怖は克服できる。恐怖は人の心の中にしか
そんざいしないからだ。
恐ろしくなったら、自分のやるべき仕事のことを一心に考えることだ。すっかり仕事に対する心構えが
できれば、恐怖心は消え去る。
デール・カーネギー
2013年8月3日土曜日
クラスとメンバ関数を定義してみる
今回はクラスとメンバ関数の定義方法をご紹介いたします^^
クラスを定義するとは、クラスの内容を記述することです。
ここでは 「ももの箱」 を例に定義をしてみます。
class PeachBox { //クラス名
public:
void Add(int addpeach); //Add, Del, Empty, GetTotalの4つはメンバ関数
void Del(int delpeach);
void Empty();
int GetTotal();
private:
int m_total; //メンバ変数 であることを明示するために m_ をつけること分かりやすい
};
ももの箱クラス(PeachBox)は、箱の中に入っているももの数を管理するクラスです。
メンバ関数GetTotal()で、箱の中にあるももの数を求めることができます。
メンバ関数を定義してみる
メンバ関数の定義の仕方は、普通に使う関数とほぼ同じようにできます。
違いと言えば、関数名の前に「クラス名::」をつけて、どのクラスのメンバ関数であるかを
記述することです。 以前少し学習した名前空間のことを思い出してください。^^
void PeachBox::Add(int addpeach) //クラス名:: この場合はPeachBox::がついています
{
m_total += addpeach; //メンバ変数に追加する桃の数を加える
}
メンバ関数の名前は、そのクラスの中だけで有効です。
クラスの外からは見えないように隠蔽(カプセル化という)されているのです(^_^.)
そのため、クラスの外側(普通の関数)や別のクラスでは同じ名前の関数を定義することができます。
メンバ関数はクラスの中で定義することもできます。
その場合は、クラスの定義をしているところで関数の中身を記述します。
class PeachBox{
public:
void Add(int addpeach);
void Del(int dellpeach);
void Empty();
int GetTotal() { //クラスの宣言と同時に中身を定義
return m_total;
}
private:
int m_total;
}
このように、クラスの中で関数の中身を定義した関数を、インライン関数と呼びます。
今日の名言
自分の欠点ばかり気になりだしたら、そんな劣等感を直してくれる人間はこの世に一人しかいない。
つまりあなた自身だ。直し方は次の言葉に尽きる。-「おのれ自身のことを忘れよ」恥ずかしくなって
きたり、気後れしたり、自分が気になりだしたら、すぐその場で何か他のことを考えることだ。人と語り合う際には、話題以外のことは一切念頭には置かない。相手がこちらのことをどう思っていようが、
こちらの話しぶりをどう思っていようが、決して気にしないことだ。自分のことは忘れて、
先を続けることだ。
デール・カーネギー
財産を失っても痛手は少ない。だが、健康を損なうと痛手は大きい。
勇気を失うと、それこそ取り返しがつかない。
作者不明
恐怖の数のほうが、危険の数より常に多い。
セネカ
クラスを定義するとは、クラスの内容を記述することです。
ここでは 「ももの箱」 を例に定義をしてみます。
class PeachBox { //クラス名
public:
void Add(int addpeach); //Add, Del, Empty, GetTotalの4つはメンバ関数
void Del(int delpeach);
void Empty();
int GetTotal();
private:
int m_total; //メンバ変数 であることを明示するために m_ をつけること分かりやすい
};
ももの箱クラス(PeachBox)は、箱の中に入っているももの数を管理するクラスです。
メンバ関数GetTotal()で、箱の中にあるももの数を求めることができます。
メンバ関数を定義してみる
メンバ関数の定義の仕方は、普通に使う関数とほぼ同じようにできます。
違いと言えば、関数名の前に「クラス名::」をつけて、どのクラスのメンバ関数であるかを
記述することです。 以前少し学習した名前空間のことを思い出してください。^^
void PeachBox::Add(int addpeach) //クラス名:: この場合はPeachBox::がついています
{
m_total += addpeach; //メンバ変数に追加する桃の数を加える
}
メンバ関数の名前は、そのクラスの中だけで有効です。
クラスの外からは見えないように隠蔽(カプセル化という)されているのです(^_^.)
そのため、クラスの外側(普通の関数)や別のクラスでは同じ名前の関数を定義することができます。
メンバ関数はクラスの中で定義することもできます。
その場合は、クラスの定義をしているところで関数の中身を記述します。
class PeachBox{
public:
void Add(int addpeach);
void Del(int dellpeach);
void Empty();
int GetTotal() { //クラスの宣言と同時に中身を定義
return m_total;
}
private:
int m_total;
}
このように、クラスの中で関数の中身を定義した関数を、インライン関数と呼びます。
今日の名言
自分の欠点ばかり気になりだしたら、そんな劣等感を直してくれる人間はこの世に一人しかいない。
つまりあなた自身だ。直し方は次の言葉に尽きる。-「おのれ自身のことを忘れよ」恥ずかしくなって
きたり、気後れしたり、自分が気になりだしたら、すぐその場で何か他のことを考えることだ。人と語り合う際には、話題以外のことは一切念頭には置かない。相手がこちらのことをどう思っていようが、
こちらの話しぶりをどう思っていようが、決して気にしないことだ。自分のことは忘れて、
先を続けることだ。
デール・カーネギー
財産を失っても痛手は少ない。だが、健康を損なうと痛手は大きい。
勇気を失うと、それこそ取り返しがつかない。
作者不明
恐怖の数のほうが、危険の数より常に多い。
セネカ
登録:
投稿 (Atom)