2006年01月26日

staticの使い方4〜静的メンバ関数(メソッド)〜

時間クラスというものを考えてみてください。時間クラスは「時刻」を取り扱う物です。では、現在の時間を表すインスタンスを得たい場合にはどうしますか?現在の時間を得る関数でもつくりますか?それとも、「現在の時刻をセットする」メソッドを時間クラスのメンバ関数として定義しますか?

// 現在の時間を表す時間クラスのインスタンスを返す関数の例
TJikanClass GetNowTime( void )
{
:
:
return nowtime;
}

// 時間クラスのメンバ関数に「現在の時刻をセットする」ものを持つ例
class TJikanClass
{
:
:

public:
void SetNowTime( void ); // 現在の時間をセットする
   :
   :
};

どちらかというと、クラスのメンバ関数に実装するよりも、関数の戻り値として現在の時間を表すインスタンスを得る方がスマートだと思います。しかしできることならば時間クラスに関わる事なのだからクラス内のメソッドとして定義したい。でも、現在の時間を得るのにインスタンスを一度作成した後メソッドを呼ぶというのは面倒くさい。
 
そこで登場するのが 静的メンバ関数 です。静的メンバ関数は、クラスのインスタンスが無くても呼び出す事ができます。つまり普通の関数と一緒なのです。異なる所は呼び出し方法です。クラス TJikanClass の中の静的メンバ関数 GetNowTimeInstance() を実行したい場合は次のように呼び出します。


// クラス TJikanClass の中の静的メンバ関数 GetNowTimeInstance() を実行する方法
TJikanClass::GetNowTimeInstance();

静的メンバ関数を定義したい場合はクラス宣言の中の、関数宣言の前にstaticをつけます。関数定義の部分にはつける必要がありません。


// 静的メンバ関数の定義例
class TJikanClass;
class TJikanClass
{
:
:

public:
static TJikanClass GetNowTimeInstance( void );
};

TJikanClass TJikanClass::GetNowTimeInstance( void )
{
:
:
return nowtime;
}

なお、静的メンバ関数はたいてい、というか100% public部で宣言します。private部や protected部で宣言したらわざわざstaticにする意味が無いでしょ?
posted by シンビアン at 07:32| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

staticの使い方2〜関数外静的変数〜

今日は関数外でstaticをつけて変数を宣言した時の動作を紹介する。
 
通常ならば、関数の外で宣言した変数は「グローバル変数」「外部変数」「大域変数」とよばれ、どの関数からも参照できる事になっている。これは便利ではあるけれども、外部変数の数が多くなると管理がしっかりできず発見しづらいバグを生む原因として忌み嫌われている。しかし、どう考えても外部変数を使った方が効率がよいという場面は多々ある。そういう場合は当然の事ながら積極的に外部変数が利用されている。
 
staticを外部変数を宣言する時に使うと、その変数の有効範囲をファイル内のみ有効と狭める事ができます。この事で、外部変数の誤使用をある程度防ぐ事ができます。

/* main.c */

static int sGStatus; /* 他のファイルでは使って欲しくないので
静的変数として宣言した */

int main()
{
sGStatus = 100;
:
:
return 0;
}
/* test.c */

extern int sGStatus; /* リンク時にエラーが発生する。 */

:
:
:
posted by シンビアン at 07:24| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

staticの使い方1〜関数内静的変数〜

staticにはいくつかの使用方法がありますが、ここでは関数内で静的変数を使う方法を紹介します。
 
関数内静的変数とは何か。一言で言うと「内容をずっと保持している変数」となります。では、普通に宣言した場合の変数とstaticをつけて、静的変数として宣言した場合との挙動の差を見てみましょう。

#include

void testfunction( void )
{
int a = 0; /* 普通に宣言した場合の変数 */
static int b = 0; /* static をつけて静的変数として宣言したもの */

a++;
b++;

printf("a = %d , b = %d\n",a,b);

return;
}

int main()
{
testfunction();
testfunction();
testfunction();

return 0;
}
実行結果
a = 1 , b = 1
a = 1 , b = 2
a = 1 , b = 3

staticをつけるとどんな感じになるかのイメージはわかりましたか?
ちなみに、宣言の時

static int b = 0;

変数名の後についている「 = 0 」は、最初に一度だけ実行されます。つまり、静的変数の初期値ですね。静的変数は外部変数と扱いが似ているので、初期値は0なのですが、例え初期値が0でもわかりやすいように「 = 0 」を入れておいたほうが良いでしょう。
 
では、どのような時に関数内静的変数が使えるでしょうか?外部変数(グローバル変数)を使わないと作れないようなものの中で、ただ単純に前回の結果を保持しておきたいだけで外部変数を使っている関数は静的変数にできます。

/* 例:呼び出すたびに0、1を交互に返す関数 */
int alternatereturn( void )
{
static int data = 0;
int result = data;

if( data == 0 ){
data = 1;
} else {
data = 0;
}

return result;
}
posted by シンビアン at 07:22| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

staticの使い方3〜静的関数〜

static宣言された関数は静的関数と呼ばれ、関数外静的変数と同じように関数の有効範囲が定義されているファイル内のみ有効で、定義されているファイル外では利用できなくなります。
これは、オブジェクト指向のカプセル化(情報隠蔽)に似ています。

一口メモ
カプセル化というのは、誰でも利用できる関数や変数は極力少なくする事を言います。
これは、他の人(外部のファイル)は絶対に呼び出してはいけない、もしくは呼び出す必要が無いような関数は外部から見えなくしてしまった方が誤使用が減り、安全性が高くなるとい考えに基づいています。

静的変数を作る方法はいたって簡単で、プロトタイプ宣言の頭と関数定義の頭に static と書くだけです。注意点としては、静的関数のプロトタイプ宣言をヘッダファイルに書いてはいけません。これは静的関数の性質を考えれば当然の事ですが、一応頭に入れておいてください。


/* 静的関数の関数プロトタイプ宣言の例 */
static int testfunction( int value );


/* 静的関数の関数定義の例 */
static int testfunction( int value )
{
int a;
    :
    :
    :
return a;
}
posted by シンビアン at 07:19| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

2006年01月21日

Nokia6630 ノキア [携帯電話 Vodafone 6630 Nokia 702NK テーマ Theme]

Nokia6630 ノキア [携帯電話 Vodafone 6630 Nokia 702NK テーマ Theme]
posted by シンビアン at 15:04| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

仮想関数

C++言語では仮想関数という特別なメソッドをクラスに持たせることが出来ます。これは,基本となるクラスで定義しておき,派生先のクラスでは同じメソッド名で別の処理を行わせるということを目的としています。もともとオブジェクト指向言語ではクラスはインスタンス化(newを使って作成)するというのが前提でしたが,C++ではそこらへんを曲げてみて,自動変数としても扱えるような使用になっています(実際多くのC++の参考書はそういった使い方をメインにしています)。しかし,オブジェクト指向的なプログラムはインスタンス化して初めて真価を発揮するのです。

例えば,他のコンピュータや器機と通信をするようなクラスを設計したとします。この際に汎用性を抑えていけば早く作成することが出来るかもしれませんが,通信相手が変わってしまった場合にはまた1から作りなおすか内部コードの一部を改造していくという羽目になるかと思います。しかし,ある基本となるクラスの設計(例えば文字を送信するときはこの関数を使用するなど)を行い,そのクラスを派生させることで,通信方法は派生先でさまざまだけれども,同じコードで相手と通信できるということも出来るようになります。これを上手に利用するには仮想関数が必要不可欠になってきます。

よく派生元のクラスのメソッドと同じ名前を定義するだけで仮想関数と同じような振る舞いをするという仮想関数と多重定義を間違えている事があります。次のサンプルコードはその実装の違いを示すものです。

class TFoo
{
protected:
int FValue;

public:
TFoo(){FValue=0;};

void ShowValue(){
ShowMessage(FValue);
}

void IncValue(){
FValue++;
}

virtual void VirtualIncValue(){
FValue++;
}
};

class TFooEx : public TFoo
{
public:

void IncValue(){
FValue+=2;
}

void VirtualIncValue(){
FValue+=2;
}
};

このコードでは基本となるクラスTFooからTFooExを派生させています。それぞれのクラスを実行してみると次のような結果が出てきます。

 まず,継承元のクラスを実行させる

// 継承元のクラスのメソッドを実行
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TFoo foo1,foo2;

foo1.IncValue();
foo2.VirtualIncValue();

ShowMessage("foo1="+foo1.Value() + ", foo2="+foo2.Value());
}

結果は foo1=1 , foo2=1と表示されます。

次に,派生先のクラスを実行させます。

// 派生先のクラスのメソッドを実行
void __fastcall TForm1::Button2Click(TObject *Sender)
{
TFooEx foo1,foo2;

foo1.IncValue();
foo2.VirtualIncValue();

ShowMessage("foo1="+foo1.Value() + ", foo2="+foo2.Value());
}
結果は foo1=2 , foo2=2と表示されます。

 次にTFoo*にインスタンス化したクラスを実行してみます。

//---------------------------------------------------------------------------
// インスタンス化したクラスを実行
void __fastcall TForm1::Button3Click(TObject *Sender)
{
TFoo *foo1=new TFooEx(),*foo2=new TFooEx();

foo1->IncValue();
foo2->VirtualIncValue();

ShowMessage("foo1="+foo1->Value() + ", foo2="+foo2->Value());

delete foo1,foo2;
}
結果は foo1=1 , foo2=2と表示されます。

違いがおわかりいただけましたでしょうか?インスタンス化させた場合には,virtualが付いているメソッドは派生先のメソッドが呼ばれ, virtualが付いていないメソッドは基本クラスのメソッドが呼ばれています。そうなるとなんでもかんでもvirtualを付ければよさそうになってきますが,そうすると派生先のクラスの自由度が奪われてしまうかもしれません。一番奇麗なコードはvirtualメソッドはprotected:に書きます。publicメソッドは出来るだけvirtualで定義してはいけません。

class TFoo
{
protected:
virtual void DoVirtualMethod();

public:
void VirtualMethod(){
DoVirtualMethod();
}
};

 少々冗長なコードになりますがしっかりとしたクラス設計をするにはこれが一番奇麗に書けると思っています(好みにもよりますが)。

 最近はあまり業界標準という言葉を聞かなくなったMFCですが,MFCではこのようなオブジェクト志向的な要素が抜けているように思えます。OWL (Object Windows Liblary)とかを使ったことのある人の多くにMFCは汚いと言う人がいますが,私も同感です。
posted by シンビアン at 14:27| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

コールバック関数

callback function

 C言語およびC++言語などにおいて、関数呼び出しの際に、関数のアドレスをパラメータとして渡すことで、呼び出した関数から自身の提供する関数を呼び出すようにすることがある。この際の呼び出した関数から実行される関数をコールバック関数と呼ぶ。

 C/C++言語だけでなく実行モジュールのアドレスをパラメータとして渡すことのできる言語なら同様のコールバック処理が実現できる。Windowsでは、ウィンドウを生成する際にウィンドウに発生するイベントをアプリケーションに伝えるためのコールバック関数(WinProc関数)を指定する。
posted by シンビアン at 13:39| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

コールバック関数

コールバック関数を使うときにはWindowsに呼び出してもらいたい関数(コールバック関数)のアドレスを指定して関数をコールします。そうする事によって、Windowsが指定されたこちらの中の関数を呼び出してくれます。しかも、こちらが要求する情報がなくなるまで(中断もしようと思えば出来ますが)ひたすら呼んでくれます。コールバック関数を通してこちらが受け取る情報をどう扱うかは、プログラマの勝手です(^^)。とにかく、「プログラムが」ではなく、「Windowsが」プログラムの中の関数を呼び出すのです。これがコールバック関数と言われる所以です。たとえてみれば、「ここの住所に情報を届けておいてね。届いたら(そこに居るやつが)処理をするからどんどん届けてね」とやるわけです。
posted by シンビアン at 13:33| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

コールバック関数

まず、「call back」という単語を英和辞典で調べると、「(電話を)後で掛け返す。」とでていました。電話でのコールバックは、相手先にダイヤルして、通じれば、自分の電話番号を伝えて電話を切り、相手方から電話の掛かってくるのを待つことをいいますが、コールバック関数も同じように、ある関数に、コールバックしてもらう関数を教えて、関数が呼び出されるのを待つことをです。

#include

/* コールバック関数 */

typedef int (*TEST_CALLBACK)(int i); /* コールバック関数のかたち */

int test_a(int mode,TEST_CALLBACK b)
{
static TEST_CALLBACK a=NULL;
int rc;

if(mode==1) { /* コールバックする関数を設定 */
a=b;
return 0;
}
if(a==NULL) {
printf("コールバック関数が設定されていません");
return 0;
}
rc=a(1); /* test_b()を呼び出す */
printf("test_a() rc=%d\n",rc);

return 0;
}

int test_b(int i)
{
printf("test_b() i=%d\n",i+100);
return i+200;
}

int main(void)
{
test_a(0,NULL); /* コールバック関数を設定しないで呼び出す */
test_a(1,test_b); /* コールバック関数を設定する */
test_a(0,NULL); /* ここから呼び出しても面白くないが、テストのため */
return 0;
}

typedefでコールバックする関数のポインタを宣言します。サンプルプログラムのなかでは
  typedef int (*TEST_CALLBACK)(int i);
と、しています。
test_b()関数はコールバックされる関数です。test_a()関数はコールバック関数を呼び出す関数ですが、サンプルのプログラムでは単純に、コールバック関数のポインタを事前に記憶させておき、コールバック関数を呼び出します。実際のプログラムでは、呼び出すタイミングがキー入力であったりとか、割り込みが起きたときとか、処理の途中経過を教えるものだったりとかになると思います。
posted by シンビアン at 13:30| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

ステルスコールバック

コールバックの際にISDNの発信者番号通知機能を用いることで、通常のコールバック機能では必要な着信後のホストの認証を省略してコールバックする機能。通常のコールバックで必要なユーザ側の課金を省略することができる。

 ステルスコールバックを行なう際は、まず、通常のコールバックと同じようにホストに対して発信を行なう。このとき、ホストは着信拒否を行ない、番号通知によって得られたユーザの電話番号宛にダイヤルアップを行ない、コールバック接続される。ユーザ側はホスト側に一度も着信しない(コールするだけ)ため、ユーザ側に一切課金されることなくコールバックを行なうことができる。

 ステルスコールバックはメーカーにより「無課金コールバック」などと呼ばれることもあるが、基本的な機能は同一である。しかし、ステルスコールバックの規格は各社ごとにまちまちで統一されていない。このため、ステルスコールバックを行なうためにはホストが用いているTAと同じメーカー、同じ機種のTAを用いなければならないなどの制約が生じる。
posted by シンビアン at 13:26| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

コールバック

電話回線などによる通信において、いったん通信先を呼び出し、相手側からの発信を求めること。

 通信料金は相手側が負担することになるため、企業の従業員が業務で社内ネットワークにダイヤルアップ接続する場合に用いられる。実際には、あらかじめ設定を行なうことにより、一連のコールバック手続きを自動で行わせる。

 コールバックの具体的な手続きについては数種類あり、通信元からの最初の呼び出しに際して若干の通信料金が必要な方式(実際に接続してすぐに切断する方式)と、最初の呼び出しに通信料金がかからない方式(無課金方式)に大別される。

 課金を要する方式については、Windows NTに搭載されているMS-CBCP方式が事実上の標準となっているが、無課金方式に関しては規格が乱立している状態で、通信元と通信先で対応している規格が異なる場合は無課金でのコールバックはできない(実際につながなければならない)。

 他に、同じ区間の通信を行なう場合でも発信地によって通信料金が異なることを利用して、通話料を安くするコールバックサービスもある。特に、この格差の大きい国際電話においては、コールバックによって通信料金が安い国から発信を行なうよう調整することで、料金を低く抑えることができる。
posted by シンビアン at 13:25| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

ハーネスとは

簡単にいうと「ゲーム基板とコントロールボックスの間で電源・映像・サウンド・操作などの信号を伝達するためのケーブル」ということになります。アーケードゲームにはなくてはならない重要な役割を果たしています。
posted by シンビアン at 13:19| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

誰が確保、解放するのか不明確なポインタメンバ変数を持つ

深刻度:★★★ - 重い深刻度

[症状]

不定値のポインタにより,メモリ破壊やメモリリークを引き起こしやすくなり,しかも原因が特定しにくく,バグを取るのに苦労をします。最初はうまく行っても,プログラムの変更でバグを誘発しやすくなります。

[原因]

ポインタの確保と解放に関する挙動をどうするか深く考えずにプログラムを作っていたなど。

[対策/予防]

コンストラクタでポインタメンバ変数をNULLに初期化するか,最初から意味のある値をセットしておくとよいでしょう。また確保と解放はクラスの外部ではなく,クラスの内部の責任とし,デストラクタで確実に解放するようにしましょう。

[例外]

なし。

[備考]

ポインタ関連のバグはあい変わらずC++でも,おなじみのものです。ただしC++では,メンバ変数がポインタであったとしても,コンストラクタで不定値でなくするようにし,デストラクタで明確に解放するという,ちょっとした注意を払うだけで,わりあい簡単に対処できるはずです。(が,そうアドバイスしても,できないと頭をかかえる人はいるんですがね。:-P)
posted by シンビアン at 12:43| Comment(0) | TrackBack(1) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

API

Application Program Interface

 アプリケーションプログラムインターフェイス。

 APIは、OSがアプリケーションに対して公開しているプログラムインターフェイスで、アプリケーションは、基本的にすべての処理をこのAPIを経由して行なう。現在一般的なOSのAPIは関数の形式をとっており、アプリケーションからは、適当なパラメータ(引数)を指定して、APIの関数を呼び出す。
posted by シンビアン at 12:40| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

システムコール

system call

 OS(のカーネル部分)が提供する機能のうち、プロセスから呼び出せるようになっている機能、もしくはその呼び出し規約のこと。ファイルアクセスやメモリの割り当て、子プロセスの生成などの機能が用意されていることが多い。

 最近のOSでは、システムコールではなく、API(Application Program Interface)という用語を使うことが多い。これは、OSのバージョンアップなどによって、従来はカーネルが提供していた機能がライブラリや別プロセスによって提供されるようになるなど、実装方法が多様化していることに対応したものである。
posted by シンビアン at 12:39| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

setjmp


文法:

#include
int setjmp( jmp_buf 環境バッファ );

setjmp()関数はlongjmp()を実行するために、システムのスタック情報を環境バッファ に保存する関数である。最初にsetjmp()を実行するときには返値はゼロである。その後、longjmp()が呼ばれた場合には、longjmp()の2番目の引数がsetjmp()の返値として返される。longjmp()の説明も参照のこと。
関連トピック:
longjmp()
posted by シンビアン at 12:38| Comment(0) | TrackBack(1) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

longjmp

文法:

#include
void longjmp( jmp_buf 環境バッファ, int 状態 );

longjmp()は最後にsetjmp()が呼ばれた位置のコードから実行を開始する。環境バッファ はsetjmp() を呼んだときにセットされる。状態 はsetjmp()の返値になり、どこのlongjump()から飛んできたのかを判断するために使用することができる。状態 はゼロに設定してはならない。
関連トピック:
setjmp()
posted by シンビアン at 12:37| Comment(0) | TrackBack(1) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

setjump(), longjump() はCの言語体系

前投稿にもlongjump とあって、何の事か解りませんでしたが、C言語の関数なんですね。

setjump()で戻り箇所を設定して、longjump()で先程設定したsetjump()へ戻る。
この際、サブルーチンの壁を超えて一気に戻れる。
posted by シンビアン at 12:35| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

setjump(), longjump()

setjump(), longjump() はCの言語体系で正式に使用が認められている。
Cで goto を使うには一つの関数内でなければならないが、longjump() はこれより酷い振る舞い
をする。

つまり、 goto の使用を非難するならば、 longjump() はそれ以上に非難されなければ
ならない。
posted by シンビアン at 12:34| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

C++で書ける! 携帯電話用OS Symbian OSプログラミング

Symbian固有の内容というのは、具体的にSymbian OSの主な基本型(charはTInt8など)、クラスの命名規約(スタックヒープに割り当てられるクラスはTで始める(前述のTInt8も同様)、CBaseクラスから派生し、ヒープに割り当てられるクラスはCではじめる、など)、例外キャッチのトラップハーネス(記事にもあるが、Cのsetjump()/longjump()に似ている)、リーブとクリーンアップ・スタックを併用することによる資源の解放忘れの防止といったところである。なお、資源の解放忘れといった場合、プログラミング上の不注意で発生するというより、むしろ、たとえばアプリケーションが途中で例外をスローして異常終了するようなとき(資源に限りがあるので、たとえば、メモリのアロケーションができないなんてことも(PC上で動作するアプリケーションに比べて)よく発生しうる)に、いかにつかんでいる資源を解放し、スタックの状態を元に戻すのか、といった感じである。
posted by シンビアン at 12:28| Comment(0) | TrackBack(0) | Symbian OS C++ 実践開発技法 | このブログの読者になる | 更新情報をチェックする

広告


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

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

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