そろそろC++やるぞパート14 ポインター ~ ポインターの初期化とメンバーアクセス「->」と「.」の違い ~
そろそろC++やります
そろそろC++をやります。そろそろC++をやりたいからです。
何回やるかはわかりません。基礎を理解するまではやろうと思います。
という感じでやっています。
※ 初心者がメモレベルで記録するので、技術記事としてはお力になれないかもしれません。
内容
生ポインターの初期化
初期化にはnew
を使用します。ヒープ配列の場合はこのように書きます。
int *ar = new int[5]{3, 5, 6};
また、MyClass
という自作クラスの場合は、new 型名()
と書きます。
MyClass *mc = new MyClass();
この宣言で初期化した場合はヒープ領域にメモリが確保されるため、delete
でメモリの解放を行う必要があります。
delete[] ar; delete(mc);
ポインターメンバーアクセス演算子
演算子のドキュメントを参考にします。
->
演算子は、ポインターの間接参照と、メンバーアクセスが組み合わされます。pubicな変数X
と関数Print
を持ったMyClass
クラスについて考えます。
class MyClass { public: int X; void Print() { cout << "Hello" << endl; } };
->
演算子を使用して、このようにアクセスすることができます。
MyClass *mc = new MyClass(); mc->X = 124; int x = mc->X;
また、ポインターの間接参照とメンバーアクセスを明示的に書くこともでき、以下の二つは同じことを表している。
int x = mc->X; int x = (*mc).X;
今回扱っているクラスは、ポインターとして扱う場合ですが、以前触れたクラスでは、クラスを変数として扱っていました。
MyClass mcClass = MyClass(); mcClass.X = 13;
メンバー変数を->
演算子でアクセスするか、.
演算子でアクセスするかはこの違いです。
void*ポインター
void
へのポインターは、単に生のメモリの場所を指します。
(実際は違うかもしれませんが、自分のイメージは全てのポインター型の基本型です。)
様々な型のポインターをvoid *
に代入することができます。
int *intPtr = new int(); float *floatPtr = new float(); MyClass *mcPtr = new MyClass(); void *voidPtr = intPtr; voidPtr = floatPtr; voidPtr = mcPtr;
C#で基底クラスのobject
に変換することがないように、C++のvoid *
ポインターもあまり使うことはないように思います。
関数へのポインター
自分の認識では、C#でいう delegate
やAction
のようなものです。
コードを見た方がわかりやすいので、先にコードを見ます。
void PrintHello(string name) { cout << "Hello " << name << endl; } void PrintWorld(string name) { cout << "World " << name << endl; } class MyClass { public: int X; void (*PrintX)(string); }; int main() { MyClass *mc = new MyClass(); mc->PrintX = PrintHello; mc->PrintX("topaz"); mc->PrintX = PrintWorld; mc->PrintX("zzz"); return 0; } // Output: // Hello topaz // World zzz
MyClass
のpublicに定義されている、void (*PrintX)(string);
が関数ポインターです。string
を受け取りvoid
を返すPrintX
を定義しています。
関数ポインターへの代入(割り当て)は=
で行います。
mc->PrintX = PrintHello; mc->PrintX = PrintWorld;
呼び出しは、通常の関数と同じように( )
で行います。
mc->PrintX("topaz"); mc->PrintX("zzz");
関数ポインターへ代入を行う前に実行すると、segmentation fault
が起こるので注意が必要です。
コンストラクタでの代入も行えます。(クラスのコンストラクタ)
class MyClass { public: MyClass(void (*f)(string)) : PrintX(f) { } void (*PrintX)(string); };
参考記事
感想
クラスの要素へのアクセス方法で->
と.
の違いが分からなかったのですが、->
は間接参照とメンバーアクセスが組み合わされていると知れたのがよかったです。
また、C#でAction
などを多用するので関数へのポインターも必要機能だなと思いました。
次回は、いろいろなところで進められているスマートポインターについて行おうと思います。