Linux/Windows Proxy 越えまとめ [開発環境]
Linuxの場合
bash
~/.profile
export http_proxy=http://proxy.example.com:PORT/
export https_proxy=http://proxy.example.com:PORT/
apt-get
/etc/apt/apt.conf
Acquire::ftp::proxy "ftp://proxy.example.com:PORT/";
Acquire::http::proxy "http://proxy.example.com:PORT/";
Acquire::https::proxy "https://proxy.example.com:PORT/";
yum
/etc/yum.conf/. proxy=http://proxy.example.com:PORT
wget
/etc/wgetrc
http_proxy=http://proxy.example.com:PORT
gem
コマンド
gem install rails --http-proxy http://proxy.example.com:PORT
git
① Corkscrewのインストール
② 設定ファイル(git-proxy)の作成
#!/bin/bash
CORKSCREW=`which corkscrew`
$CORKSCREW 192.168.111.15 8080 $1 $2
③ 設定ファイルの属性変更とインストール
# chmod 755 git-proxy
# mv git-proxy /usr/local/bin/
④ 起動設定
# vi /etc/profile
—————————————-
//最終行に以下を追加# git-proxy
export GIT_PROXY_COMMAND=/usr/local/bin/git-proxy
Windowsの場合
コマンド
> C:\Windows\system32>netsh winhttp set proxy proxy-server="http=proxy.example.com:PORT"
または
> set HTTP_PROXY=proxy.example.com:PORT
Git の基本 [開発環境]
Ⅰ. Git とは
システムの詳細については沢山のサイトがあるので割愛します。参考として以下のサイト等があるので必要であれば参照のこと。
- http://ja.wikipedia.org/wiki/Git
- http://www8.atwiki.jp/git_jp/pages/15.html
- http://blog.asial.co.jp/894
Ⅱ. Git インストール
WindowsでGitを利用するには、CygwinとMYSYSを利用する2つの方法がある。今回は両方の方法でインストールしてみた。
◆Cygwin版
Cygwinはインストール済みとして進める。Cygwinのインストール方法については以下参照のこと。
① Cygwinのsetup.exeを起動する。
② パッケージ選択画面のSearch欄に”git”と入力し、必要なパッケージを表示する。
③ ここで以下のパッケージを選択する。
- git Git本体
- git-completion Gitの自動補完を行うためのもの
- git-gui GUIビューア(要らない)
- git-svn GitからSubversionリポジトリにアクセスする際に必要
- gitk gitk()
⑤ Cygwinターミナルからgitがインストールされたことを確認する。
◆MYSYS版
① 以下のmysysgitのサイトからインストーラをダウンロードする。
② ダウンロードしたインストーラを起動し、チェックアウト及びコミット時に改行コードを変換の設定を「何もしない」に変更し、あとはデフォルトのままインストールを行う。
③ インストールが完了すると、コマンドライン版の"Git Bash"とGUI版の"Git GUI"がインストールされる。
Git Bash
Git GUI
以上でインストールは完了、ちなみにWEB上にはMYSYS版の情報が多いきがする。
Ⅲ. 個人の識別情報
Gitをインストールしたときに最初にすべきことは、ユーザー名とE-mailアドレスを設定することです。全てのGitのコミットはこの情報を用いるため、これは重要で、次々とまわすコミットに永続的に焼き付けられます
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
Ⅳ. Git コマンド
とりあえず使いそうなコマンド:
git init
バージョン管理相性のフォルダに移動してからこのコマンドを実行することで、.gitフォルダが出来、バージョン管理の対象になる。
git add
コミットするファイルを指定する。
.(ピリオド) :現在のワークツリーの状態を記録する。
-u :ワークツリー内のすべてのファイルを記録する。
-A :新しく作成されたファイルを含めてインデックスに記録する。
-p :どの変更が次回のコミットに含めるかを選択して、インデックスに記録する。
git commit
変更をコミットする。
-m “最初のコミット” :コメントをログメッセージとして記録できる。
-a –m “ログメッセージ” :ワークツリー内のファイルすべての現在の状態を記録したコミットを作成する。
-v :git commint, git diff の結果がまとめて表示される。
--amend :ひとつ前のコミットを破棄して新しくコミットする。
git diff
前回の git add 以降に加えた変更が確認できる。
git status
git commitを実行した場合にどのファイルへの変更がコミットされ、どのファイルへの変更はコミットされないかと確認できる。
git checkout ファイル名
引数で指定したファイルをインデックスの状態に戻す。
git clone A.git B.git
Aリポジトリをコピーする。
git config
どのようにGitが見えて機能するかの全ての面を制御できる設定変数を取得し、設定することができます。
ちなみにプロキシの設定は以下となります。
git config --global http.proxy http://host:port
他にもあるが、ここでは最小限のコマンドのみの解説とした。他のコマンド説明は以下で確認できる。
- http://sourceforge.jp/magazine/09/03/16/0831212
- http://npnl.hatenablog.jp/entry/20101107/1289121576
- http://blog.digital-squad.net/article/123090058.html
- http://kray.jp/blog/review-git-commands/
Windowsでの処理時間取得[C言語] [開発環境]
Windowsでミリ秒単位で処理時間を計算するために使う関数に、GetTickCountとtimeGetTimeが良く使われる。timeGetTime関数は1msの精度を持っており、一般にGetTickCountより良いと言われている。さらにQueryPerformanceCounterとSleepを使った場合の分解能を比較した。
動作テストとしては、コンテック製デジタルIOボードの出力をON/OFFするアプリを作成し、結果のパルスをオシロスコープで確認した。
結果としては、高分解能パフォーマンスカウンタが存在する場合は、QueryPerformanceCounter、存在しない場合は、timeGetTimeが良さそうであった。ちなみに高分解能パフォーマンスカウンタの有無はQueryPerformanceCounter関数で確認できる。
GetTickCount
システムを起動した後の経過時間を、ミリ秒(ms)単位で取得します。この時間は、システムタイマの分解能による制限を受けます。
DWORD GetTickCount(VOID);
パラメータ
なし
戻り値
関数が成功すると、システムを起動した後の経過時間が、ミリ秒単位で返ります。
解説
経過時間は DWORD 型で保存されています。システムを 49.7 日間連続して動作させると、経過時間は 0 に戻ります。
より高い分解能のタイマが必要な場合は、「」(マルチメディアタイマ)または「」(高分解能タイマ)を使います。
テスト
DWORD st; // 開始時間
DWORD now; // 現在時間
DWORD pass=10; // 経過時間(msec)while (1) {
st = GetTickCount();while (1) {
now = GetTickCount();
if ((now - st) > pass) break;
}if (ledOn == true) {
Ret=DioOutBit(Id, 4, 0);
if (Ret!=0) {
printf("DioOutBit off NG[0x%x]\n",Ret);
}
ledOn=false;
}
else {
Ret=DioOutBit(Id, 4, 1);
if (Ret!=0) {
printf("DioOutBit on NG[0x%x]\n",Ret);
}
ledOn=true;
}
}
passパルス幅を10ms以下に設定しても、実動作は15ms以下にはできない。この関数はWindowsのシステムタイマーの設定以下にはできない。またGetTickCount()関数によるシステムタイマー分解能の変更にも対応していないことも再確認できた。
timeGetTime
関数を使用するためにはwinmm.libをリンクし mmsystem.hをインクルードする。 GetTickCountと同様にWindows起動からの経過時間をミリ秒単位で返す。 timeBeginPeriod,timeEndPeriodを使うことで精度の調整をすることができる。 デフォルトで5ミリ秒に設定されており、最高で1ミリ秒の精度指定が可能
DWORD timeGetTime(VOID);
パラメータ
なし
戻り値
関数が成功すると、システム時刻がミリ秒単位で返ります。
解説
timeGetTime 関数で返される値は DWORD 値であることに注意してください。戻り値は 0 ミリ秒から 2^32 ミリ秒の間を循環します。2^32 ミリ秒は約 49.71 日にあたります。計算に timeGetTime 関数の戻り値を直接使うようなコードでは、特にコードの実行を制御する場合などに、問題が発生する可能性があります。計算では常に、2 つの timeGetTime 関数の戻り値の差を使います
テスト
int i=0;
DWORD st; // 開始時間
DWORD now; // 現在時間
DWORD pass=1; // 経過時間(msec)// システムタイマーの分解能を1ミリ秒に設定
timeBeginPeriod(1);
while (1) {
st = timeGetTime();
while (1) {
now = timeGetTime();
if ((now - st) > pass) break;
}if (ledOn == true) {
Ret=DioOutBit(Id, 4, 0);
if (Ret!=0) {
printf("DioOutBit off NG[0x%x]\n",Ret);
}
ledOn=false;
}
else {
Ret=DioOutBit(Id, 4, 1);
if (Ret!=0) {
printf("DioOutBit on NG[0x%x]\n",Ret);
}
ledOn=true;
}i++;
if (i>50000) break;
}
// 分解能を戻す
timeEndPeriod(1);
GetTickCount()関数と同様に、単純にtimeGetTime()関数を呼ぶだけでは、システムタイマーの影響を受けて、15ms以下にはできなかった。しかしtimeBeginPeriod()/timeEndPeriod()関数を入れることで最小約2ms幅のパルスを出力する事が可能となることが確認できた。
QueryPerformanceCounter
高分解能パフォーマンスカウンタが存在する場合、そのカウンタの現在の値を取得します。
LARGE_INTEGER構造体に、高分解能パフォーマンスカウンタの現在値が格納される。 QueryPerformanceFrequencyを使うことでカウンタの周波数を知ることが できるので、カウンタの差分を周波数で割れば処理時間を算出できる。1ミリ秒よりも小さい 間隔で測定可能。
BOOL QueryPerformanceCounter(
LARGE_INTEGER *lpPerformanceCount // カウンタの値
);
パラメータ
1 個の変数へのポインタを指定します。関数から制御が返ると、この変数に、高分解能パフォーマンスカウンタの現在の値が格納されます。インストール先のハードウェアが高分解能パフォーマンスカウンタをサポートしていない場合、この変数に 0 が格納されることがあります。
戻り値
インストール先のハードウェアが高分解能パフォーマンスカウンタをサポートしている場合、0 以外の値が返ります。
関数が失敗すると、0 が返ります。拡張エラー情報を取得するには、 関数を使います。たとえば、インストール先のハードウェアが高分解能パフォーマンスカウンタをサポートしていない場合、この関数は失敗します
解説
マルチプロセッサのコンピュータを使っている場合、どのプロセッサを呼び出しても問題はありません。ただし、BIOS または HAL(ハードウェアエミュレーションレイヤ)のバグが原因で、異なったプロセッサを呼び出すと、異なった結果を取得する可能性があります。特定のスレッドに対するプロセッサの親和性を指定する(特定のスレッドでただ 1 つのプロセッサを使うよう指定する)には、 関数を使います
テスト
int i=0;
LARGE_INTEGER nFreq, nStart, nNow;
DWORD dwTime;
DWORD pass=1; // 経過時間(msec)//変数の初期化
memset(&nFreq, 0x00, sizeof nFreq);
memset(&nStart, 0x00, sizeof nStart);
memset(&nNow, 0x00, sizeof nNow);
dwTime = 0;QueryPerformanceFrequency(&nFreq);
while (1) {
QueryPerformanceCounter(&nStart);
while (1) {
QueryPerformanceCounter(&nNow);
dwTime = (DWORD)((nNow.QuadPart - nStart.QuadPart) * 1000 / nFreq.QuadPart);
if (dwTime >= pass) break;
}if (ledOn == true) {
Ret=DioOutBit(Id, 4, 0);
if (Ret!=0) {
printf("DioOutBit off NG[0x%x]\n",Ret);
}
ledOn=false;
}
else {
Ret=DioOutBit(Id, 4, 1);
if (Ret!=0) {
printf("DioOutBit on NG[0x%x]\n",Ret);
}
ledOn=true;
}i++;
if (i>50000) break;
}
QueryPerformanceCounter()関数を使用することでシステムタイマーの設定変更なしに1ms幅のパルスを出力する事ができた。
Sleep
参考にSleep()関数を使用したパターンもテストした。なおシステムタイマーの影響を受けることが明確だったので、最初からtimeBeginPeriod()/timeEndPeriod()関数を入れてテストした。
VOID Sleep(
DWORD dwMilliseconds // 中断の時間
);
パラメータ
実行を中断する時間を、ミリ秒(ms)単位で指定します。0 を指定すると、現在のスレッドは、優先順位が等しく実行の準備ができているほかのスレッドに残りのタイムスライスを譲ります。そのようなスレッドが存在しない場合は、この関数は即座に制御を返します。INFINITE を指定すると、実行が無制限に中断されます。
戻り値
なし
解説
指定された時間にわたって、現在のスレッドの実行を中断します。
テスト
long Ret=0;
bool ledOn= false;
DWORD pass=1; // 経過時間(msec)while (1) {
// 分解能を1ミリ秒に設定
timeBeginPeriod(1);
Sleep(pass);
// 戻し
timeEndPeriod(1);if (ledOn == true) {
Ret=DioOutBit(Id, 4, 0);
if (Ret!=0) {
printf("DioOutBit off NG[0x%x]\n",Ret);
}
ledOn=false;
}
else {
Ret=DioOutBit(Id, 4, 1);
if (Ret!=0) {
printf("DioOutBit on NG[0x%x]\n",Ret);
}
ledOn=true;
}
}
timeGetTime()関数とほぼ同じ、2ms幅のパルスを得ることが出来た。
C++ 指定ビットのON/OFF [開発環境]
指定したビットのみ、ONまたはOFFする機能。
- now_data : 現在のビット状態
- write_bit : ビット操作するビット番号
- next_data : ビット操作後のデータ用
// 書き込むByteデータ
short next_data;
if (pol >= 1) {
next_data = write_bit | now_data; // 1とORでBitオン
}
else {
next_data = ~write_bit & now_data; // 0とのANDでBitオフ
}
操作例
ONする場合
01010100
00000001 OR
---------------
01010101
OFFする場合
01010101
11111110
---------------
01010100
C/C++ 振る舞いを動的に変化する [開発環境]
voidポインタ
- void ポインタにはほとんどのポインタをキャストなしで代入できる。
- void ポインタからは直接参照できない。
- void ポインタから他のポインタへの代入にはキャストが必要。
- void ポインタは型を不問でアドレスを受け取る引数に使う。
関数ポインタ
関数ポインタは、アドレスを格納する関数と同じ戻り値の型のポインタ変数を用意します。
仮引数がある場合は、続けて仮引数も指定します。
宣言時には、優先順位の関係から必ずポインタ名に ( ) をつけます。
型 (*変数名) (仮引数);
関数のエントリポイントをポインタに格納すれば、このポインタから関数を呼び出せます。
こうすることで、間接参照で関数を呼び出しすることができるのです。
関数のポインタで注目するべきは、間接参照であることです。
ポインタに関数のアドレスを代入できるというのは、非常に斬新なことです。
これまで、関数を呼び出すには直接関数名を指定する以外にありませんでした
しかし、間接参照することで関数の配列を実現することができます。
関数の配列がどれだけ斬新なものかは想像がつくでしょう。
この機能によって、プログラムの実行時に直接実行する関数を指定することができます。
しかも、非常に簡易にです。
#include <stdio.h> void kitty(void); void sakura(void); void hina(void); int main() { void (*po[])() = { kitty , sakura , hina }; int i; printf("実行する関数の番号を指定してください 0~2>"); scanf("%d" , &i); if ((i < 0) | (i > 2)) return 0; (*po[i])(); return 0; } void kitty() { printf("Kitty on your lap\n"); } void sakura() { printf("Card Captor SAKURA"); } void hina() { printf("LOVE HINA"); }
クラスの場合
class SuperClass
{
public:
virtual void method_1() = 0;
virtual void method_2() = 0;
};
class classA : public SuperClass
{
public:
virtual void method_1() { cout << "A::method_1" << endl; }
virtual void method_2() { cout << "A::method_2" << endl; }
};
class classB : public SuperClass
{
public:
virtual void method_1() { cout << "B::method_1" << endl; }
virtual void method_2() { cout << "B::method_2" << endl; }
};
利用側では、
auto_ptr<SuperClass> obj;
obj.reset( new classA() );
obj->method_1(); // classA::method_1が呼び出される
obj->method_2();
obj.reset( new classB() );
obj->method_1(); // classB::method_1が呼び出される
obj->method_2();
auto_ptr とは
std::auto_ptr<_Ty> クラス
書式
std::auto_ptr<I> obj(new CR);
使い方は非常に簡単で、コンストラクタにインスタンスを放り込むだけです。
仕組みは非常に分かりやすくて、obj という自動オブジェクトがスコープを抜けて 解体されるときに、デストラクstd::auto_ptr<_Ty>::~auto_ptr がプロパティとして持つ インスタンスを delete してくれる
オペレータ
get() メソッド
_Ty* std::auto_ptr<_Ty>::get(void)const;
というメソッドを経由することで、ポインタ変数を引数として要求する関数にも、 渡すことが出来ます。
reset() メソッド
void std::auto_ptr<_Ty>::reset(_Ty* _Ptr)
というメソッドにインスタンスを渡すと、それまで持っていたインスタンスを安全に 解体しつつ、新しいインスタンスをプロパティとして持ちます。
所有権を持つポインタ変数への代入は本来厳禁ですが、reset() メソッドを経由することで、 そのような操作が安全に行えるわけですね。
release() メソッド
もし、所有権を別の変数に渡さなければならないような状況になった場合は、
_Ty* std::auto_ptr<_Ty>::release(void);
とすることで、この戻り値を代入した先の変数に所有権を渡します。 当然、所有権を渡された変数は、責任を持って解放する必要があります。
C++ クラス -インターフェースクラス- [開発環境]
参考サイト
◆インターフェースクラス
名前の通り、クラスの一種ですが、少々特徴的なものです。 なお、単にインタフェースと呼ぶこともありますし、抽象クラスと呼ぶこともあります。 (インタフェースクラスという言葉は、C++以外で使われることが多く、どちらかというと C++ では使われる頻度の低い言葉ですが、 本サイトではこの言葉で統一します)。
インタフェースクラスは、メンバ変数を持たず、メンバ関数だけで構成されます。 そして、それらのメンバ関数は、宣言だけされていて定義がありません。 定義のないメンバ関数を持っている都合上、インタフェースクラスをインスタンス化することもできません。 一見、何のために存在しているか分からないですが、インタフェースクラスは、継承して使うためにあります。 そして、定義のないメンバ関数達は、オーバーライドして使います。
書式
// インタフェースクラスの定義
class IPen
{
public:
// 線を描く
virtual void DrawLine(int sx, int sy, int ex, int ey) = 0;
};
上のようにすると、IPen という名前のインタフェースクラスを実現できます。 繰り返しますが、C++には直接的にインタフェースクラスは用意されていません。 他の言語、例えば Java というオブジェクト指向言語なら「interface」というキーワードが用意されています。
これまでのクラス定義と違うのは、メンバ関数の宣言方法だけです。 最後に「=0」が付いており、これを付けると、そのメンバ関数の定義を省略できます。 定義が省略されるので、このクラスをインスタンス化することはできなくなります。 インスタンス化できてしまうと、定義が省略されたメンバ関数を呼び出そうとするかも知れないからです。
なお、先頭の「virtual」キーワードも必要です。 virtualの付いたメンバ関数を仮想関数というのでしたが、更に末尾に「=0」を付けると、純粋仮想関数と呼ばれます。
なお、クラス名の先頭に「C」ではなく「I」を付けました。 もちろんInterfaceの意味です。これは、通常のクラスとの区別に役立ちます。
このように、C++では、直接的にインタフェースクラスを記述できず、純粋仮想関数を宣言してやることで、 インスタンス化を妨害するような形で実現させています。
そのため、メンバ変数を追加したり、純粋仮想関数でないメンバ関数を加えたりすることもできてしまいます。 しかし、それらを加えた時点で、厳密にはインタフェースクラスとは呼べなくなります。 実際、Java の interface では、メンバ変数を宣言できなくなっており、メンバ関数も自動的に純粋仮想関数扱いになるようになっています (今は C++編なので関係ないですが、Java ではメンバ変数やメンバ関数という用語は使いません。また純粋仮想関数とも呼ばないです)。
コーディング例
先程定義した IPenインタフェースクラスを使ってみましょう。 前述の通り、インタフェースクラス(というより、純粋仮想関数を含んでいるクラス)はインスタンス化ができません。 そのため、必ず継承を行い、そのサブクラス側の方をインスタンス化することになります。
// pen.h
// CColorPenクラスで使う線の色
#define BLACK (0)
#define RED (1)
#define BLUE (2)
#define GREEN (3)
// インタフェースクラスの定義
class IPen
{
public:
// 線を描く
virtual void DrawLine(int sx, int sy, int ex, int ey) = 0;
};
// 黒いペンのクラス
class CPen : public IPen
{
public:
// 線を描く
void DrawLine(int sx, int sy, int ex, int ey);
};
// 色ペンのクラス
class CColorPen : public IPen
{
public:
// コンストラクタ
CColorPen();
// 線を描く
void DrawLine(int sx, int sy, int ex, int ey);
// 線の色を設定する
void SetColor(int color);
private:
// 線の色
int m_color;
};
まず、クラス定義は上のようになります。 インタフェースクラスといえど、C++ では普通のクラスと定義の方法自体は変わらないので、普通に継承できます。 そして、純粋仮想関数は、特別な形の仮想関数に過ぎないのでオーバーライドできます。オーバーライドした純粋仮想関数の定義の仕方についても、何も特別なことはありません。 普通のメンバ関数と同じです。ほとんど、オーバーライドと同じですが、メンバ関数の定義は次のようになります。
// pen.cpp
#include "pen.h"
// 黒い線を描く
void CPen::DrawLine(int sx, int sy, int ex, int ey)
{
// 黒い線を描く
}
// CColorPenクラスのコンストラクタ
CColorPen::CColorPen()
{
m_color = RED; // 赤いペンを初期カラーとする
}
// 現在設定されている色で線を描く
void CColorPen::DrawLine(int sx, int sy, int ex, int ey)
{
// m_colorを参照して、その色で線を描く
}
// 線の色を設定する
void CColorPen::SetColor(int color)
{
m_color = color;
}最後にmain関数を見てみます。// main.cpp
#include "pen.h"
int main()
{
CPen pen;
CColorPen color_pen;
pen.DrawLine( 10, 10, 100, 100 ); // 黒い線を描く
color_pen.SetColor( BLUE ); // 青色を設定
color_pen.DrawLine( 20, 20, 200, 200 ); // 青い線を描く
return 0;
}
やはりオーバーライドと変わりません(色は変えましたが)。 ここで、試しに次のようにしてみてください。
IPen ipen;
するとコンパイルが通らないことが分かります。 理由は IPenクラスには純粋仮想関数が含まれているからです。デストラクタを宣言するときに、virtualキーワードを付けると、仮想デストラクタになります。今の時点では理由が説明できないのですが、インタフェースクラスには仮想デストラクタを宣言しておくべきです。 ある状況下では、仮想デストラクタがないと処理が正しく行えません。 たとえ、デストラクタで行う処理がなくとも、仮想デストラクタだけは宣言しておきましょう。 そして、その定義は空にしておきます。
// インタフェースクラスの定義
class IPen
{
public:
// 仮想デストラクタ
virtual ~IPen(){}
// 線を描く
virtual void DrawLine(int sx, int sy, int ex, int ey) = 0;
};
C++ クラス -オーバーライド- [開発環境]
参考サイト
◆オーバーライド
継承によって作られたサブクラスは、スーパークラスのメンバを引き継ぎますが、オーバーライドを使うと、 引き継いだメンバ関数の中身を書き換えることができます。つまり、スーパークラス側とサブクラス側とで、異なる 動作をさせることができるようになるということです。
コーディング例
// pen.h
// CColorPenクラスで使う線の色
#define BLACK (0)
#define RED (1)
#define BLUE (2)
#define GREEN (3)
// 黒いペンのクラス
class CPen
{
public:
// 線を描く
virtual void DrawLine(int sx, int sy, int ex, int ey);
};
// 色ペンのクラス
class CColorPen : public CPen
{
public:
// 線を描く
void DrawLine(int sx, int sy, int ex, int ey);
// 線の色を設定する
void SetColor(int color);
private:
// 線の色
int m_color;
};// pen.cpp
#include "pen.h"
// 黒い線を描く
void CPen::DrawLine(int sx, int sy, int ex, int ey)
{
// 黒い線を描く
}
// 現在設定されている色で線を描く
void CColorPen::DrawLine(int sx, int sy, int ex, int ey)
{
// m_colorを参照して、その色で線を描く
}
// 線の色を設定する
void CColorPen::SetColor(int color)
{
m_color = color;
}
オーバーライドを行うためには、スーパークラス側のメンバ関数に「virtual」 というキーワードを付けます。virtualを付けて宣言されたメンバ関数のことを、仮想関数 と呼びます。
そして、メンバ関数の定義ですが、スーパークラス側もサブクラス側も、両方とも定義を記述します。そのため、 両者の内容を変えれば、動作を変更できるわけです。CPenクラス側のDrawLineメンバ関数を呼び出すと、黒い線が描かれ、 CColorPenクラス側のDrawLineメンバ関数を呼び出すと、現在の色で線が描かれるようにします。
main関数の方は、次のようにしたとします。
// main.cpp
#include "pen.h"
int main()
{
CPen pen;
CColorPen color_pen;
pen.DrawLine( 10, 10, 100, 100 ); // 黒い線を描く
color_pen.SetColor( RED ); // 赤色を設定
color_pen.DrawLine( 20, 20, 200, 200 ); // 赤い線を描く
return 0;
}
C++ クラス -継承- [開発環境]
参考サイト
http://www.geocities.jp/ky_webid/index_old.html
http://www.s-cradle.com/developer/sophiaframework/tutorial/Cpp/inherit.html
◆継承(インヘリタンス)
クラスには継承と呼ばれるメカニズムがあり、これにより既存のクラスの再利用性が高まります。継承を使うと次のようなことが実現できます。
- 既存クラスに機能を追加した新しいクラスを定義する。
- 既存クラスの挙動をカスタマイズした新しいクラスを定義する。
クラスの継承による機能追加
ここに鉛筆があるとします。鉛筆には芯があり、書くたびにどんどん小さくなっていきます。これをクラスにしてみましょう。
class Pencil
{
private:
SIntN core; // 鉛筆の芯の長さ
public:
Void Write()
{
core -= 1; // 書くたびに芯が 1mm ずつ小さくなる
if (core < 0) core = 0;
}
};
あるとき、鉛筆の後ろに消しゴムをくっつけた新製品が売り出されました。消しゴム付き鉛筆です。消しゴム付き鉛筆は、鉛筆と同じ機能をもちながら、さらに消しゴムの機能ももっています。
このように機能が追加されたクラスは次のように定義することができます。
class ErasePencil : public Pencil
{
private:
SIntN rubber; // 消しゴムの大きさ
public:
Void Erase()
{
rubber -= 1; // 消すたびにゴムが 1 立方mm ずつ小さくなる
if (rubber < 0) rubber = 0;
}
};
class キーワードに : public Pencil を指定することで、Pencil のメンバ変数とメンバ関数を引継ぐことができます。つまり、ErasePencil はメンバ変数 core とメンバ関数 Write() をもっています。それに加えて、新しく定義したメンバ変数 rubber とメンバ関数 Erase() ももっています。したがって、次のようなコードを書くことができます。
ErasePencil pen;
pen.Write(); // Pencil クラスから引き継いだメンバ関数の呼び出し
pen.Erase(); // ErasePencil クラスで新たに定義したメンバ関数の呼び出し
このように、既存のクラスのメンバを引き継ぐことを継承といいます。引き継ぎの元となるクラスを基底クラス、引き継いで新しく定義したクラスのことを派生クラスといいます。「ErasePencil は Pencil の派生クラスである」とか「Pencil は ErasePencil の基底クラスである」という言い方をします
Windows7でgrepを使う [開発環境]
フレームワークなどの膨大なファイルから必要な文字列を所在を検索するために、Linuxではgrepコマンドが使われる。これをWindows7上で行う方法を調べた。
1. cygwinのダウンロードとインストール
このサイトから"setup.exe"をダウンロードします。
setup.exe を起動します。
インストール先を”e:\cygwin”に変更しました。ここは各自の環境により変更してください。
インターネットへの接続方法を指定します。
日本のサイトを選びました。
パッケージの選択画面です。あとから変更可能なので、ここではデフォルトのまま進みます。
完了です。
2. Cygwinの確認
デスクトップにできたCygwinアイコンを起動します。
grepのバージョンを確認してみる。
3. Cygwinを使う
① cドライブにアクセスする。
“mount”コマンドで現在のマウントポイントを確認する。
cドライブは、”/cygdrive/c”にマウントされている事がわかる。
cドライブへ移動し、”ls”コマンドでファイル内容を確認してみる。
“c:\”のファイルが確認できている。
② フォルダ移動
grepしたいディレクトリに移動する。スペースや()等の特殊記号が含まれるホルダーへの移動は記号の前に”\”を追加します。例えば、
”c:\Progeam Files (x86)” へ移動する場合、以下と記述します。
$ cd c:\Program\ Files\ \(x86\)
③ grepする
書式
$ grep [オプション] パターン ファイル
◆ <INtime>フォルダー以下にあるファイル群から”BEFORE_INIT”を含むファイルを探すには。
$ grep –n –r BEFORE_INIT INtime
◆ ヘッダーファイルのみを対象に検索する場合。
$ find INtime –name *.h | xargs grep –n –r BEFORE_INIT
xargs はfind で見つかった全ファイルのパスを、一度に grep に渡している。
オプションは
-b:行のブロック番号をつける
-c:パターンに一致した行の行数のみを出力する
-h:複数ファイルを指定した際にファイル名を出力しない
-i:大文字小文字を区別しない
-l:パターンに一致した行を含むファイル名だけを出力する
-n:パターンに一致した行のファイル内での行番号を出力する
-s:エラーメッセージのみを出力する
-v:パターンに一致しない行のみを出力する
–color:一致文字列に色を付ける
-o:一致した文字列だけを出力する
-r:特定ディレクトリ以下を再帰的に検索する
スタティックライブラリの作成と使用(C++) [開発環境]
1. スタティックライブラリ プロジェクトの作成
① [ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。
② プロジェクトの種類ペインで、[Visual C++] の [win32] をクリックします。
③ テンプレート ペインの [Win32 コンソール アプリケーション] をクリックします。
④ プロジェクトとして「MathFuncsLib」などの名前を付け、[プロジェクト名] フィールドに入力します。ソリューションとして「StaticLibrary」などの名前を付け、[ソリューション名] フィールドに入力します。
⑤ [OK] をクリックして、Win32 アプリケーション ウィザードを起動します。[Win32 アプリケーション ウィザード] ダイアログ ボックスの [概要] ページで、[次へ] をクリックします。
⑥ Win32 アプリケーション ウィザードの [アプリケーションの設定] ページで、[アプリケーションの種類] の [スタティック ライブラリ] を選択します。
⑦ Win32 アプリケーション ウィザードの [アプリケーションの設定] ページで、[追加のオプション] の下にある [プリコンパイル済みヘッダー] の選択を解除します。
⑧ [完了] をクリックして、プロジェクトを作成します。
2. クラスを追加する。
① 新しいクラスのヘッダー ファイルを作成するには、[プロジェクト] メニューの [新しい項目の追加] をクリックします。[新しい項目の追加] ダイアログ ボックスが表示されます。カテゴリ ペインで、[Visual C++] の [コード] をクリックします。テンプレート ペインの [ヘッダー ファイル (.h)] をクリックします。ヘッダー ファイルとして「MathFuncsLib.h」などの名前を付け、[追加] をクリックします。空白のファイルが表示されます。
② 加算、減算、乗算、除算などの一般的な数値演算を行うための、MyMathFuncs という名前の単純なクラスを追加します。コードは次のようになります。
// MathFuncsLib.h
namespace MathFuncs
{
class MyMathFuncs
{
public:
// Returns a + b
static double Add(double a, double b);
// Returns a - b
static double Subtract(double a, double b);
// Returns a * b
static double Multiply(double a, double b);
// Returns a / b
// Throws DivideByZeroException if b is 0
static double Divide(double a, double b);
};
}
③ 新しいクラスのソース ファイルを作成するには、[プロジェクト] メニューの [新しい項目の追加] をクリックします。[新しい項目の追加] ダイアログ ボックスが表示されます。カテゴリ ペインで、[Visual C++] の [コード] をクリックします。テンプレート ペインの [C++ ファイル (.cpp)] をクリックします。ソース ファイルとして「MathFuncsLib.cpp」などの名前を付け、[追加] をクリックします。空白のファイルが表示されます。
④ ソース ファイルに MyMathFuncs の機能を実装します。コードは次のようになります。
// MathFuncsLib.cpp
// compile with: /c /EHsc
// post-build command: lib MathFuncsLib.obj
#include "MathFuncsLib.h"
#include <stdexcept>
using namespace std;
namespace MathFuncs
{
double MyMathFuncs::Add(double a, double b)
{
return a + b;
}
double MyMathFuncs::Subtract(double a, double b)
{
return a - b;
}
double MyMathFuncs::Multiply(double a, double b)
{
return a * b;
}
double MyMathFuncs::Divide(double a, double b)
{
if (b == 0)
{
throw new invalid_argument("b cannot be zero!");
}
return a / b;
}
}
⑤ プロジェクトをスタティック ライブラリにビルドするには、[プロジェクト] メニューの MathFuncsLib Properties… をクリックします。左ペインで、[構成プロパティ] の下の [全般] をクリックします。右ペインで、[構成の種類] を [スタティック ライブラリ (.lib)] に変更します。[OK] をクリックして、変更を保存します。
⑥ [ビルド] メニューの [ソリューションのビルド] をクリックし、スタティック ライブラリをコンパイルします。これにより、他のプログラムで使用できるスタティック ライブラリが作成されます。
3. このスタティックライブラリを参照するアプリケーションを作成する
① 作成したスタティック ライブラリを参照して使用するアプリケーションを作成するには、[ファイル] メニューの [新規作成] をポイントし、[プロジェクト] をクリックします。
② プロジェクトの種類ペインで、[Visual C++] の [win32] をクリックします。
③ テンプレート ペインの [Win32 コンソール アプリケーション] をクリックします。
④ プロジェクトとして「MyExecRefsLib」などの名前を付け、[プロジェクト名] フィールドに入力します。[ソリューション] の横のドロップダウン リストで、[ソリューションに追加] をクリックします。これにより、スタティック ライブラリと同じソリューションに新しいプロジェクトが追加されます。
⑤ [OK] をクリックして、Win32 アプリケーション ウィザードを起動します。[Win32 アプリケーション ウィザード] ダイアログ ボックスの [概要] ページで、[次へ] をクリックします。
⑥ Win32 アプリケーション ウィザードの [アプリケーションの設定] ページで、[アプリケーションの種類] の [コンソール アプリケーション] を選択します。
⑦ Win32 アプリケーション ウィザードの [アプリケーションの設定] ページで、[追加のオプション] の下にある [プリコンパイル済みヘッダー] の選択を解除します。
⑧ [完了] をクリックして、プロジェクトを作成します。
4. アプリケーションからスタティックライブラリのを使用するには
① 新しいコンソール アプリケーションを作成すると、空のプログラムが作成されます。ソース ファイルの名前は、前の処理でプロジェクトに付けた名前と同じになります。この例では、「MyExecRefsLib.cpp」という名前です。
② スタティック ライブラリで作成された数値演算ルーチンを使用するには、それを参照する必要があります。このためには、[プロジェクト] メニューの [参照] をクリックします。[プロパティ ページ] ダイアログ ボックスで、[共通プロパティ] ノードを展開し、[参照設定] をクリックします。次に、[新しい参照の追加] ボタンをクリックします。[参照] ダイアログ ボックスの詳細については、「[参照設定] ([<プロジェクト名> プロパティ ページ] ダイアログ ボックス - [共通プロパティ])」を参照してください。
③ [参照の追加] ダイアログ ボックスが表示されます。このダイアログ ボックスには、参照できるすべてのライブラリが表示されます。[プロジェクト] タブでは、現在のソリューション内のすべてのプロジェクト、およびそれらに含まれるすべてのライブラリが表示されます。[プロジェクト] タブで、MathFuncsLib をクリックします。次に [OK] をクリックします。[参照の追加] ダイアログ ボックスの詳細については、「[参照の追加] ダイアログ ボックス」を参照してください。
④ スタティック ライブラリのヘッダー ファイルを参照するには、インクルード ディレクトリ パスを変更する必要があります。このためには、[プロパティ ページ] ダイアログ ボックスで、[構成プロパティ] ノードを展開し、次に [C/C++] ノードを展開して、[全般] をクリックします。[追加のインクルード ディレクトリ] の横に、MathFuncsLib.h ヘッダー ファイルへのパスを入力します。
⑤ これで、MyMathFuncs クラスをこのアプリケーションで使用できます。MyExecRefsLib.cpp の内容を次のコードに置き換えます。
// MyExecRefsLib.cpp
// compile with: /EHsc /link MathFuncsLib.lib
#include <iostream>
#include "MathFuncsLib.h"
using namespace std;
int main()
{
double a = 7.4;
int b = 99;
cout << "a + b = " <<
MathFuncs::MyMathFuncs::Add(a, b) << endl;
cout << "a - b = " <<
MathFuncs::MyMathFuncs::Subtract(a, b) << endl;
cout << "a * b = " <<
MathFuncs::MyMathFuncs::Multiply(a, b) << endl;
cout << "a / b = " <<
MathFuncs::MyMathFuncs::Divide(a, b) << endl;
return 0;
}
5. アプリケーションの実行
① MyExecRefsLib が既定のプロジェクトとして選択されていることを確認します。ソリューション エクスプローラで [MyExecRefsLib] を選択し、次に [プロジェクト] メニューの [スタートアップ プロジェクトに設定] を選択します。
② プロジェクトを実行するには、[デバッグ] メニューの [デバッグなしで開始] を選択します。出力は、次のようになります。