「C++/C++特有の概念」の版間の差分
削除された内容 追加された内容
Toya shiwasu (トーク | 投稿記録) 「CとC++の相違点」の節を追加 |
Toya shiwasu (トーク | 投稿記録) 全体を修正 |
||
1 行
== オブジェクト指向とクラス ==
C++ではオブジェクト指向をサポートするために'''クラス'''(class)が導入されています。
オブジェクト指向は、
データと手続きを一体化して記述することで、
プログラムの内容をわかりやすくするというプログラミングの手法です。
クラスはオブジェクト指向の中核となる概念で、
様々な言語でクラスを定義することが出来ます。
C++以外ではJava, Python, Rubyなどがオブジェクト指向言語として有名です。
C++のクラス定義は、
他の言語と比べても非常に汎用的で出来ることが多く、
それだけにわかりにくい面もあります。
単純にオブジェクト指向に興味があるのなら、
PythonやRubyのオブジェクト指向の方が簡単かも知れないので、
そちらも検討してみるとよいでしょう。
== オブジェクト指向とプログラムの大きさ ==
逆に、それほど大きくないプログラムを書く時には、
オブジェクト指向はあまり役に立ちません。
具体的にどれくらいの大きさのプログラムが大きいと思うかは、
書き手の好みにもよります。
オープンソースからの具体例では、
webプラウザのMozilla Firefox、
メールソフトのThunderbird、、
オフィスソフトのOpenOfficeは、
C++で書かれています。
一方、巨大プログラムと呼ばれてもよい大きさのプログラムでも、
Cで書かれているプログラムは存在します。
例えば、
OSのLinux、
ウィンドウシステムのX Window Systemは、
Cで書かれています。
(これらのソフトウェアにCが採用された理由には、
プロジェクト立ち上げ当時のC++の普及度や安定度、
あるいは対象となるソフトウェアの扱う領域や目的等の要因があると思われ、
今まさに同様のプロジェクトをはじめた場合にもCが選ばれるかは分かりません)
== オブジェクト指向とGtk ==
オブジェクト指向が用いられる例として、
GUIのウィジェットがあります。
ウィジェットは、
ウィンドウやボタンなど、
グラフィックを作成するために用いられるオブジェクトです。
これらは共通の操作として、最大化や最小化などを持っています。
これらの操作に対応する関数をウィジェットごとに作成するのは大変な作業なので、
多くの場合これらはオブジェクト自体に操作を与えるプログラム手法がとられます。
例えば、Gtkでは、
Containerクラスとそれを継承したクラスに属するウィジェットには、
<source lang="cpp">
gtk_container_add(GtkContainer, GtkWidget)
</source>
という関数を用いてウィジェットを入れ込む作業が行われます。
このように、多くの似通ったデータを扱う際には、
オブジェクト指向プログラミングがよく用いられます。
ただし、Gtk+はCを用いてウィジェットを作成しているので、
ここでのオブジェクト指向は変則的です。
実際には、
上の例ではオブジェクト指向でいう継承という考えが用いられています。
継承とは、
似通った性質をもつクラスを複数作成する時に、
それらの差分だけを新たに書き加え、
共通の部分は既存のものを流用するという考え方です。
GtkWindowクラスは、
GtkContainerクラスを継承しているので、
GtkWindowクラスに対してもgtk_container_addを用いることが出来ます。
これは、GtkWindowだけでなく、GtkContainerを継承した全てのクラスの特徴です。
実際に継承を用いる時には、
どの部分をどのクラスで導入するかが問題になりますが、
ある程度試行錯誤を繰り返すしかなさそうです。
C++でも、クラスの継承を用いることが出来ます。
これについては後述します。
== クラスの基本 ==
'''クラス'''(class)とは、データとその操作手順であるメソッドをまとめたオブジェクトの雛型を定義したものである。
<ref>[http://e-words.jp/w/%E3%82%AF%E3%83%A9%E3%82%B9.html クラスとは|class - 意味/定義 : IT用語辞典]</ref>
=== クラスの宣言 ===
C++でクラスを宣言するには、classキーワードを用いて次のように記述する。。
<source lang="cpp">
class クラス名{
//非公開関数と変数
public:
//公開関数と変数
}オブジェクトリスト;
</source>
クラス名でクラスの名前を指定する。
クラスは多くの点で構造体と似ている。
クラスはメンバ変数の他にメンバ関数を含めることができるが、
実は構造体もメンバ関数を含むことができる。
<ref>[http://wisdom.sakura.ne.jp/programming/cpp/cpp44.html 構造体と共用体]</ref>
class内の関数と変数のことをメンバ(member)と呼ぶ。
メンバにはオブジェクトの外からアクセスできない非公開のものと、
アクセスできる公開のものがある。
classのメンバはデフォルトで非公開である。
オブジェクトリストを指定すると、
その名前のオブジェクトを作成する。
複数のオブジェクトを作成する場合は、
「,(コンマ)で区切る。
オブジェクトリストの指定は任意である。
メンバ関数が大きい場合、
クラスの宣言の外にその定義を記述することもできる。
その場合、メンバ関数の定義は、
関数名の前に「クラス名::」を付ける。
「::(コロン2文字)」のことをスコープ解決演算子(scope resoluthion operator)と呼ぶ。
次のように記述する。
<source lang="cpp">
戻り値の型 クラス名::関数名(仮引数の並び)
{
関数の本体
}
</source>
*例(メンバ関数の定義をクラスの宣言の中に書く)
<source lang="cpp">
class aaa {
int a;
public:
int getA() const {return a;}
int setA(int a){return this->a = a;}
};
</source>
*例(メンバ関数の定義をクラスの宣言の外に書く)
<source lang="cpp">
class aaa {
int a;
public:
int getA() const;
int setA(int a);
};
int aaa::getA() const
{
return a;
}
int aaa::setA(int a)
{
return this->a = a;
}
</source>
上の例では、
getA,setAというメンバ関数と、
aというintのデータを持ったクラスを定義しています。
classのメンバはデフォルトでです。
getAはaの中身を得るためのメソッドで、
setAはaを設定するためのメソッドです。
これらはaがprivateであることから必要になります。
setAでは、thisが用いられていますが、
これは与えられたクラスの性質を持つオブジェクトへのポインタを表しています。
ポインタなので、それが表すデータにアクセスする時には->を用います。
これは(*this).aと書いても同じ意味になります。
=== オブジェクトの作成 ===
オブジェクトの作成は次のように記述する。
<source lang="cpp">
クラス名 オブジェクト名;
</source>
クラス名でクラスの名前を指定する。
オブジェクト名で作成するオブジェクトの名前を指定する。
複数のオブジェクトを作成する場合は、
「,(コンマ)で区切る。
*例(ob1, ob2というaaaクラスのオブジェクトを作成する。)
<source lang="cpp">
aaa ob1, ob2;
</source>
=== メンバへのアクセス ===
メンバにアクセスするには、ドット(.)演算子を用いて次のように記述する。
<source lang="cpp">
オブジェクト名.メンバ名
</source>
*例(ob1のsetAメンバ関数を呼び出す。)
<source lang="cpp">
ob1.setA(1234);
</source>
=== オブジェクトののコピー ===
== クラスの詳細 ==
=== カプセル化 ===
カプセル化とは、オブジェクト指向のクラスにおいて、
オブジェクトが与える手法以外の手法で、
オブジェクトの持つデータに影響を与えてはいけないとする考え方です。
これはオブジェクト自身が自分のデータを扱う方法を全て提供すべきで、
それ以外の方法に頼ることはクラスの設計の問題であるとする考え方にもとづいています。
Javaなどの言語でも、
カプセル化がサポートされています。
Pythonなどの言語では、
カプセル化は(あまり)サポートされていません。
C++では、
public, private, protectedの3つのキーワードがアクセス制御として与えられています。
privateは、同じクラスに属するメソッドからしか値が呼び出すことができなくなります。
publicは、プログラムの他の部分からも呼び出せるようになります。
protectedは、クラスを継承した先から用いることが出来るようになります。
しかし、プログラムの他の部分から呼び出すことは出来ません。
<source lang="cpp">
//
#include <iostream>
using namespace std;
class aaa {
int a;
public:
int getA() const {return a;}
int setA(int a){return this->a = a;}
};
int main()
{
//ob1.a=1234;//この行はコンパイルエラーになる。
ob1.setA(1234);
cout<<"ob1のaの値は"<<ob1.getA()<<endl;
}
</source>
=== ポリモーフィズム ===
ポリモーフィズムは、
オブジェクト指向の考え方の一つで、
同一の名前で複数の異なる動作を作成し使う。
ポリモーフィズムは、
C++では関数のオーバーロードで実現される。
関数のオーバーロードとは、
複数の関数を同じ名前で作成し使うことである。
関数のオーバーロードを行うには、
単に同じ名前の関数を複数定義するだけである。
ただし、引数の型か個数が異ならなければ、
関数のオーバーロードはできない。
戻り値の型だけが異なっていてもできない。
<source lang="cpp">
//ポリモーフィズムの例
#include <iostream>
using namespace std;
int add(int a, int b);
int add(int a, int b, int c);
int main()
{
cout<<"1+2は"<<add(1,2)<<endl;
cout<<"
}
int add(int a, int b)
{
return a+b;
}
int add(int a, int b, int c)
{
return a+b+c;
}
</source>
=== 継承 ===
=== コンストラクタ関数 ===
=== デストラクタ関数 ===
== クラス・構造体・共用体の比較 ==
== 脚注 ==
|