KENスクールブログ-パソコンスクール パソコン教室 KENスクール

C++

C++の紹介2【中級者向け】

https---www.pakutaso.com-assets_c-2015-06-LISA78_MBAsawaru20141018102912-thumb-1000xauto-17983

一般的に難しいといわれているC++を紹介した記事です。
基本文法や変数、オブジェクトの概念を習得済みの中級者向けの記事です。

前回は、C++でのオブジェクトの取り扱いについて紹介しました。Javaとは異なり、代入は実体のコピーであるという内容です。
今回は、その代入(データのコピー)についてもう少し詳しく見て行きます。

#include<stdio.h>
using namespace std;

class Myclass{
    int value;	
public: 
    void setValue(int val) { value = val; };
int getValue() { return value; };
    void printValue(){ printf("%d\n",value); };
};

前回同様、上記のクラスを使って話を進めて行きます。

int main(void){
    Myclass m1;
    m1.setValue(100);
    Myclass m2 = m1;
    m2.printValue();
}

このプログラムの実行結果は、画面に100と表示されます。イコール演算子による代入でm1の内容がm2にコピーされたからです。
それでは今回の本題ですが、イコール演算子を使用しない場合でも代入が行われる(代入と同じくオブジェクトがコピーされる)場合があります。それはどのような時でしょうか。

それは、関数(メソッド)を使ってデータをやり取りした場合です。

オブジェクトを使わない、単純なデータ型でのサンプルコードで見て行きましょう。

int func(int arg){
arg += 100;	// arg = arg + 100;と同義
    int ret = arg;
    return ret;
}
int main(void){
int val = 10;
int ans = func(val);
}

func()関数はint型を受け取り、int型を返す関数です。関数内で変数argに100を加算していますが、変数valには影響しません。
このとき、変数valから変数argへ、変数retから変数ansへ、関数内では変数argから変数retへ、データが受け渡されています。特に意識していなかった人も居るかもしれませんが、この引数および戻り値のやり取りもデータのコピーが行われているのです。

それでは、オブジェクトを使った関数の例を見て行きましょう。

Myclass func(Myclassarg){
    arg.setValue( arg.getValue() + 100 );
    Myclass ret = arg;
    return ret;
}
int main(void){
Myclass val;
    val.setValue(10);
Myclass ans = func(val);
    ans.printValue();
}

このときも、変数valから変数argへ、変数retから変数ansへ、関数内では変数argから変数retへ、データが受け渡されており、それぞれの場所でデータのコピーが行われています。

今回、Myclassはサンプルとしてのクラスなので、int型変数を一つと、それに関する関数を三つ持っているだけですが、実際には多くの変数や関数を含むクラスになります。
そのときに、関数に渡すたびにコピーをしていてはメモリの無駄ですし、コピーをする処理の時間も無駄です。

Javaではこのような書き方をしたとき、オブジェクトの参照情報のコピーを渡すので、実際にオブジェクトに含まれるデータのコピーは作成されません。C++ではデータのコピーを作らず、そのデータの場所の情報を受け渡すときはポインタを使います。(参照渡しというのもありますが、それは別の機会に。)

下記のサンプルはデータのコピーを作らない、ポインタでのデータのやり取りです。

Myclass *func(Myclass*arg){
    arg->setValue( arg->getValue() + 100 );
    Myclass *ret = arg;
    return ret;
}
int main(void){
Myclass val;
    val.setValue(10);
Myclass *ans = func(&val);
    ans->printValue();
}

表示結果は一つ前のサンプルと同じですが、データをコピーしていない点で異なります。
main()関数の最後の行を val.printValue(); としても同様の結果になります。

Javaではオブジェクトの受け渡しは参照型のみで行われますが、C++では標準的には実体のコピーで行われ、ポインタを使うことでJavaの参照情報のやりとりと同様のことができるようになります。


カテゴリー: C++ プログラム

C++の紹介【中級者向け】

work-731198_640

一般的に難しいといわれているC++を紹介した記事です。
基本文法や変数、オブジェクトの概念を習得済みの中級者向けの記事です。
今回は、特に習得率の高そうなJavaに置き換えながら、C++でのオブジェクトの扱いについて、注意をしなければいけない点について解説します。

クラスの定義

まずはクラスの定義からです。このクラスを使って話を進めて行きます。

#include<stdio.h>	// ①
using namespace std;	// ①

class Myclass{
    int value;		// ②
public:				// ③
    void setValue(int val) { value = val; };		// ④
    void printValue(){ printf("%d\n",value); };		// ④
};

①Javaでのimportとpackageのようなものです。
②C++のクラス内の定義はデフォルトでprivateです。
③この記述以降はpublicになります。
④C++ではこのような書き方でメンバ関数(メソッド)を定義することはあまりしませんが、Javaの表記に近づけるためにこのような書き方をしています。

main関数

次に、main関数です。

int main(void){
    Myclass m1,m2;		// ①
    m1.setValue(10);	// ②
    m2 = m1;			// ③
    m1.printValue();	// ④
    m2.printValue();	// ④

    m1.setValue(30);	// ⑤
    m1.printValue();	// ⑥
    m2.printValue();	// ⑦

    return 0;
}

①C++の場合はこの記述だけでオブジェクトが生成されます。
②オブジェクトm1のメンバ変数に10が代入されます。
③Javaではこのような記述をした場合、参照のコピーになりますが、C++ではオブジェクトの内容のコピーになります。
④③の代入の結果、m1,m2ともに10と表示されます。
⑤②と同じく、オブジェクトm1のメンバ変数に30を代入しています。
⑥m1は⑤の結果、30と表示されますが・・・
⑦m2は10と表示されます。これは、m1とm2が別のオブジェクトだからです。

ポインタ

Javaの参照のコピーのような動きにしたい場合はポインタを利用します。

int main(void){
    Myclass *p1 = new Myclass();	// ①-a
    Myclass *p2 = new Myclass(); 	// ①-b
    p1->setValue(10); 	// ②
    p2 = p1;			 // ③
    p1->printValue();	// ④
    p2->printValue();	// ④

    p1->setValue(30);	// ⑤
    p1->printValue();	// ⑥
    p2->printValue();	// ⑥

    return 0;
}

①C++でのインスタンス化の記述方法はいくつかありますが、Javaに近い形にするならこのような形でしょうか。2つのオブジェクトを生成し、それぞれ、p1,p2で扱おうとしています。
②ポインタ変数からメンバ関数(メソッド)を呼び出す際はアロー演算子(->)を使います。
③ここでp2に代入されるのはp1のアドレス情報です。p2も①-aで生成したオブジェクトを扱えるようになりました。
④p1,p2ともに10と表示されます。
⑤p1から30をセットしています。
⑥p1,p2ともに30が表示されます。

 
これでめでたしめでたし・・・とはいきません。
①-bで生成したオブジェクトはどこへ行ってしまったのでしょうか?
Javaにはメモリの自動開放機能がありますが、C++にはありませんので、メモリ上に残ってしまいます。
今回は短いプログラムで、すぐに終了するので害はありませんが、たとえば24時間動き続けるシステムで、繰り返しこれをやってしまうとどうでしょう。メモリが開放されずにどんどん消費され、システムが停止してしまうかもしれません。

このあたりがC++は難しいと言われている原因の一つだと思います。
他にも、他言語では自動でやってくれることを、C++では自分で書かなければいけないことがあります。しかし、「自分で記述することができる」とも言い換えられます。
細かなメモリ管理をしなければいけないが、細かなメモリ管理をすることができる。C++とはそんな言語なのです。


カテゴリー: C++ プログラム