実は、ワテはオブジェクト指向を十分には理解出来ていない。
プログラミング歴は長いのだが、その中でもC言語の経験が長い。
C++に関しては、その思想を理解するまでに何年も掛かった。
いや別に数年間ずっと勉強し続けても理解出来なかったと言う訳では無くて、オブジェクト指向入門みたいな本をちらっと立ち読みしてみても、
- カプセル化(情報隠蔽)
- ポリモーフィズム (多態性)
- インヘリタンス(継承)
- ポリモフィズム(多態性)
- ダイナミックバインディング(動的束縛)
- オーバーライド(上書き)
- オーバーロード(多重定義)
いきなりこんな聞いた事も無い専門用語の解説から始まる解説本しか無かったから、最初の数ページを読んで挫折する。
では、C++のサンプルプログラムを試してみようと思って例題を見ると、
#include <iostream> int main(int argc, char* argv[]) { std::cout << "Hello World!" << std::endl; return 0; }
こんな例から始まる場合が多い。
当時のワテは、
オブジェクト指向とは、
printf("文字列\n");
の代わりに
std::cout<< "文字列" << std::endl;
と書く事かと思っていた。アホやがな。
でも真面目にそう思っていた。
単に文字列を画面に出力するだけなのに、何でこんなヘンテコな文法にするのかその必然性が全く理解出来なかった。
その当時のワテと同じく、C言語は知っているけれどC++は難しくて分からないと言う人向けに、その後のワテがどのようにC++を習得したのか書いてみたい。
Visual Studioを使う
Visual Studioを使うと、各種の言語が使える。
- VB.NET
- C#
- C (注意)
- C++
- C/CLI
- JavaScript, PHP, Python, その他いろいろ
VB.NETはいわゆるBasic言語の.NET Framework版だ。
それ以前はマイクロソフトのBasicと言えばVisual Basicと言われる製品だったが、.NETの登場以降はVB.NETに置き換えられた。
機能的にはBasic言語を使って、ビジュアルの名の通りグラフィカルなユーザーインタフェースを作る事が出来る。
VB.NETの例
ワテは最初このVB.NETを覚えて、GUIなどを作っていた時期がある。
このVB.NETでコンソールプロジェクトを作るとモジュールというのが生成されて、
Module Module1 Sub Main() End Sub End Module
こんなふうになる。
ファイル名もデフォルトでは
Module1.vb
のようになる。
一方、メニューの中に「クラスを追加」と言うのがあるので、追加してみると、
Public Class Class1 End Class
こんなのが追加される。
ファイル名は
Class1.vb
となる。
つまり、VB.NETを使うと必然的にクラスというのが出てきてオブジェクト指向的なプログラムを書く事が可能なのだ。
でも実は、VB.NETの場合には、クラスを使わずにモジュールだけを使ってプログラムを書く事も可能だ。
当時のワテはこのClassというのが全く理解できていなかったのでModuleだけでプログラムを書いていた記憶がある。
なので、もし今でもMicrosoft Visual Basic 6.0 というVBの最終版を使い続けている人は、VB.NETに移行してもModuleのみを使えばクラスが良く分からなくてもプログラムを書く事は可能だと思う。
ちなみにワテはVB6などの古い言語は経験がない。
さて、ワテはその次に、C#を覚えた
C#を覚えた
Cシャープのコンソールプロジェクトの場合には、
namespace CSharpConsoleApp3 { class Program { static void Main(string[] args) { } } }
これが雛形となる。
Main関数自身がclassの中にある。
また、重要な点は、VB.NETにあったようなModuleというものが無いのだ。
なので、C#をやる場合はクラスだけでプログラムを書く必要がある。
と言う事は、クラスとは何かを理解しないとC#プログラムが書けないのだ。
この当時のワテは、冒頭に書いたように
オーバーライド(上書き) override
オーバーロード(多重定義)overload
などが全く理解できていない状態だった。紛らわしい用語を使うなよと言いたい。
さらに似たような単語に
オーバーライト(上書き) overwrite
がある。
もうこのオーバーなんちゃら三兄弟だけで訳ワカメだった。
あるいはC++で文字列を画面に出力するだけなのに、
std::cout<< "文字列" << std::endl;
何なんだよこれは!
と言う感じで、C++やオブジェクト指向と言う物は何でこんなにややこしいのかなあ、さっぱり分からん状態だった。
まあ、今思えばちょっと恥ずかしいかなり低レベルな次元での挫折状態である。
C#でクラスを使う
C#でクラスMyClassを定義してみた。
namespace CSharpConsoleApp3 { class Program { static void Main(string[] args) { MyClass mc = new MyClass(); mc.i = 10; } } class MyClass { public int i; public string s; private string s_private; } }
そのMyClassを
MyClass mc = new MyClass();
としてnewで実体mcを作るのだ。
そのmcの中にあるpublic変数は外部のMainから利用可能で、
mc.i = 10;
として使える。一方、private変数のs_privateは外部に公開されていないので、Mainの中で
mc.s_private = "文字列";
とは出来ない。
クラスとは構造体みたいなもん
こんな感じでC#のクラスを覚えたワテは、
「な~んや、クラスって構造体みたいなもんやがな!」
という感想だった。
まあ、確かにそんな理解で良いと思う(多くのお叱りがあるかもしれないが)。
この時に、世間では、変数とは言わずにメンバーとかメンバー変数と言う場合が多いが、ワテは単純に変数と言う方が馴染みやすい。
一方、newで作成したmcはMyClassの実体であるが、それを世間ではインスタンスと呼ぶらしい。何でもかんでも外国語で呼べばいいと思っているのかどうか知らないが、日本人なら日本語で実体と言って欲しい。
メソッド
で、クラスの場合には、変数 i, s, s_privateだけでなく、関数を入れる事も可能だ。
sumfunc()という足し算をする関数を入れてみた。
namespace CSharpConsoleApp3 { class Program { static void Main(string[] args) { MyClass mc = new MyClass(); mc.i = 10; int sum = mc.sumfunc(10); Console.WriteLine("sum={0}", sum); } } class MyClass { public int i; public string s; private string s_private; public int sumfunc(int iend) { int sum = 0; for (int i = 0; i <= iend; i++) { sum += i; } return sum; } } }
その関数をMainの中から
int sum = mc.sumfunc(10);
として10まで足し算している。
要するにクラスMyClassをnewで実体化しておけば、その中にあるパブリックなメンバ変数やメンバ関数を普通に使えると言う訳だ。
なお、世間ではメンバ関数の事をメソッド(Method)などと言うようだが、ワテはメンバ関数のほうが馴染みやすい。あるいはメンバも日本語で仲間あたりに置き換える方が良いかも。仲間関数、どうかな⁉
なお、仲間由紀恵さんとは一切関係ない事は間違いない。
で、
そもそもなぜnewで実体化する必要があるのか?
当時のワテはそういう疑問が解消しなかった。
まあ、クラスとは構造体みたいなもんだと思えば、C言語で構造体を動的に確保するなら、
#include "stdafx.h" #include <iostream> struct MyStruct{ int i; char p[100]; }; int main(int argc, char* argv[]) { auto ptr = (MyStruct*) malloc(sizeof(MyStruct)); // ここで実体を確保 ptr->i = 10; printf("i=%d\n", ptr->i); free(ptr); // ここで解放 return 0; }
こんな風にmalloc/freeを使ってメモリの確保/解放を行うから、C++のnew/deleteはそれと同じようなもんかな(ワテの理解では)。
これをC++のクラスに置き換えると、同じくmalloc/freeを使って
#include "stdafx.h" #include <iostream> class MyClass{ public: int i; char p[100]; private: char p_private[100]; }; int main(int argc, char* argv[]) { auto ptr = (MyClass*)malloc(sizeof(MyClass)); ptr->i = 10; printf("i=%d\n", ptr->i); free(ptr); return 0; }
としても良いし、
あるいはnewやdeleteを使うなら、こんな感じか。
#include "stdafx.h" #include <iostream> class MyClass{ public: int i; char p[100]; private: char p_private[100]; }; int main(int argc, char* argv[]) { auto ptr = new MyClass(); // newして ptr->i = 10; printf("i=%d\n", ptr->i); delete ptr; // 使い終わったらdeleteして解放 return 0; }
と言う事で、まとめてみるとこんな感じか。
C++, Java, Objective-Cなどのオブジェクト指向言語 | C言語 |
---|---|
クラス | 構造体に関数を入れたもの |
メンバ変数 | 変数の事 |
メンバ関数やメソッド | 関数の事 |
newやdelete | mallocとfree |
あくまでワテの理解なのでC++やオブジェクト指向専門家の人からお叱りを受けるかもしれないが。
コンストラクタ
C++などのオブジェクト指向言語の教科書にはコンストラクタと言う文字が良く出て来る。
和風が好きなワテとしては、外国語のカナカナ表記には馴染みにくい。
まあ、それはおいといて、C++でコンストラクタの例だ。
#include "stdafx.h" #include <iostream> class MyClass{ public: MyClass(int i, char p[100]){ // 引数を二個取るコンストラクタ this->i = i; strcpy_s(this->p, p); } int sumfunc(int iend){ int sum = 0; for (int i = 0; i <= iend; i++){ sum += i; } return sum; } public: int i; char p[100]; private: char p_private[100]; }; int main(int argc, char* argv[]) { auto ptr = new MyClass(20, "hello kitty!");//コンストラクタに初期値 printf("i=%d\n", ptr->i); printf("p=%s\n", ptr->p); delete ptr; return 0; }
実行結果
i=20 p=hello kitty!
まあ、コンストラクタというのは、newで実体化する時に、そのクラスが持っているメンバ変数に初期値を与えるなどの用途に使う奴だ。
日本語では、
構築子(コンストラクタ Constructor)
と言うらしい。
見てきたような嘘をつく人か。
それは、講釈師。
コンストラクタと関数の違い
コンストラクタの定義の仕方は、基本的には普通の関数定義と同じだ。
引数を与える事も出来る。
普通の関数と違う点は、
- 関数名が任意ではなくて、そのクラス名と同じ名前にする
- intやvoidなどの戻り値を指定しない
の二点がコンストラクタと普通の関数の大きな違いだ。
まとめ
と言う事で、ワテの経験に基づいて、C++やオブジェクト指向のさわりの部分をワテ流に説明した。
見てきたような嘘をつくのは、ワテかも知れないので皆さん注意が必要だ。
なお、
- カプセル化(情報隠蔽)
- ポリモーフィズム (多態性)
- インヘリタンス(継承)
- ポリモフィズム(多態性)
- ダイナミックバインディング(動的束縛)
- オーバーライド(上書き)
- オーバーロード(多重定義)
などは、C++でプログラムを書いていると徐々に自然に覚えられると思う。
妙にややこしくて難しそうなカタカナ英語なので取っ付きにくいだけであり、その考え方とか使い方は簡単だ。
その辺りは、この第一回目のオブジェクト指向入門記事に大反響があれば、第二回目の記事として紹介したい。
C++はCの上位互換性がある
ちなみに、現在のワテは未だにこのC++のヘンテコな文法
std::cout<< "文字列" << std::endl;
には全く馴染めないので、C言語の
printf("文字列\n");
を使っている。
C++はCの上位互換性があるのでそういう点では、C++でプログラムを書く場合でも、プログラムの殆どの部分をC言語で書いて、必要に応じてC++の便利機能を少し使うなどの書き方でも良い。
例えば文字列の処理では、C言語のchar[100]配列を使うよりも、C++のstd::string型を使うほうが遥かに便利で手軽だ。
文字列の連結や部分文字列の取出しなど、C言語なら毎回ヌル文字 \0 の存在を意識しなくてはならない処理が、C++を使うとそんな煩わしい事を一切考えなくても自由自在に文字列処理が可能だ。
std::coutでは見損なったが、std::stringではC++ を少しは見直した。
書籍で勉強する
今世間で話題のC++の本らしい。
ローレベルではなくてロベールさんの著作と言う意味らしい。
フランス人かと思ったが、日本人だった。
ちなみに、ワテのこのブログ記事は、ローレベルで分かり易い記事を目指している。
文字通り
ローレベルなC++入門講座 ワテ
ロベールのC++入門講座 ロベール氏
これくらいでは笑点の司会にはなれない。
コメント