OFとC++初心者の日記

OpenFrameworks と C++をハローワルドする日記

【C++】ファイル構成・ポインタ・thisについて

ハローkyonです

今日は

http://download.bnn.co.jp/download/beyond_interaction/BNN_BeyondInteraction.pdf

のp145から勉強したよ^^

今日はファイルの構成とポインタとthisについて勉強します

ファイル構成について

ーーー
【.h ヘッダーファイル】
他のファイルでも利用できるように定義を記述します
例:クラスの定義が入っています
下記のようなものです

class testApp : public ofBaseApp {
public:
void setup();
void update();
void draw();
float phase; //位相
float frequency; //周波数
};
#endif

ちなみにクラスには、void update();のような関数と
float phase;のような変数でできています。
float phase;のようなクラスの変数一つ一つをフィールドといいます

【.cpp 実装コード】
例:下記のようなクラスの実装コードが入っている

void testApp::setup(){
sampleRate = 44100; //サンプリング周波数
amp = 0.5; //音量
pan = 0.5; //左右の定位
phase = 0; //位相
frequency = 440; //周波数
152 | 153
ofSoundStreamSetup(2, 0, this); //サウンドストリームの準備、左右2ch
}

ーーー

これを念頭に置かないとわからなくなりますね

続いて

ポインタについて

p145ページに

main.cpp

#include "ofMain.h"
#include "testApp.h"
#include "ofAppGlutWindow.h"
int main(){
ofAppGlutWindow window;
ofSetupOpenGL(&window, 1024,768, OF_WINDOW);
testApp* test2 = new testApp();
ofRunApp(test2);
}

というコードがあります。
ポインタの説明をわかりやすくするために

testApp* test2 = new testApp();
ofRunApp(test2);

を書き換えました。
newの返り値は、必ずtestApp*のように、hogehoge*になります。
なので、変数を定義するときの型はhogehoge*になります。
*はポインタを表しています

ここで、疑問が。。。new testApp()って何だ?
これが何かを理解するためには、ポインタを理解する必要があります。

■ポインタとは
ポインタはメモリを参照している変数で
普通の変数には、インスタンスが入っていますが、
ポインタにはインスタンスのメモリ上の場所が入っています。

ちなみに、インスタンスとはクラスを利用する時に作るものです。
インスタンスを作るとクラスで定義したフィールドがメモリ上で確保されます。

わかりにくいので例えば下記のようなコードの場合の
メモリとポインタの関係について具体的に説明します

int main(){
 testApp test1;//test1はtestAppのスタック上のインスタンス
 testApp* test2 = new testApp();//test2はtestAppのヒープ上のインスタンス
 testApp* test3 = &test1;
ofRunApp(test2);
}


まず、メモリにはStackとHeapがあります

f:id:kyon_ha:20160619190114j:plain

■Stack
testApp test1;のように記載する場合です
関数が呼び出された時に自動的に用意されるメモリです。
関数が呼び出された時に自動的に追加され終わるときに消えます。
下から順番に追加されます。

■Heap
testApp* test2 = new testApp();のように記載する場合です
自分でメモリを確保できます。
確保するには、下記のように記載します

new testApp();

メモリリーク
スタックと違いnewで作ったもの(Heapでメモリ領域を確保したもの)は必ず

delete test2;

このように消さないと残ってします。 Stack内のポインタが消えたけど、Heapの領域が残ったままで参照もできない状態をメモリリークといいます。
メモリリークが多すぎるとそのままメモリの使用量が増え、パソコンのメモリが足りなくなってプログラムがクラッシュします

new testApp();

ちなみに、この場合だと
メモリは確保されるけど、ポインタがないから利用できないのでメモリリークですね

■StackでのインスタンスとHeapのインスタンスの使い分けについて

これまで説明してきたように、インスタンスには2種類の作り方があります
Stackでのインスタンスでも利用できるし、
Heapのインスタンスも利用できます。

 testApp test1;//test1はtestAppのスタック上のインスタンス
 testApp* test2 = new testApp();//test2はtestAppのヒープ上のインスタン

Stackのパフォーマンスが高いからできるだけStackを利用したいですが、
たとえば今の関数が終わってからでもそのインスタンスを利用したい場合に、Heapのインスタンスを作ります。

thisとポインタの関係について

ちなみに、P154にこのようなコードがあります。

testApp.cpp

#include "testApp.h"
void testApp::setup(){//testAppというクラスのsetupという関数
sampleRate = 44100; //サンプリング周波数
amp = 0.5; //音量
pan = 0.5; //左右の定位
phase = 0; //位相
frequency = 440; //周波数
152 | 153
ofSoundStreamSetup(2, 0, this); //サウンドストリームの準備、左右2ch
}

この「this」は何を表しているのでしょう

ofSoundStreamSetup(2, 0, this); //サウンドストリームの準備、左右2ch

thisの意味は今のインスタンスへのポインターという意味です。
例えば、

#include "testApp.h"
main(){
 testApp test1; 
 test1.setup();
}

まず、test1はtestAppのインスタンスです

この場合、setupの中のthis
つまり上記のコードの
ofSoundStreamSetup(2, 0, this); がtestAppのインスタンス(test1)へのポインタになります。
ポインターは、そのもののインスタンスへのポインターとしても利用できるし、
その先祖クラスのインスタンスのポインタとしても利用できます

ofSoundStreamSetup(《出力チャンネル数》,《入力サンプル数》,
《ofSimpleAppへのポインタ》)

このコードの場合は、おそらくtestAppの祖先クラスがofSimpleAppなので、コードはこのようにかけるわけです。
(このコードのofBaseApp の定義をみないとわからない)