« C4D C.O.F.F.E.E.SDK GeModalDialogの頁の誤 | トップページ | C4D C.O.F.F.E.E. クラスを使うには…_02 »

C4D C.O.F.F.E.E. クラスを使うには…_01

クラスを自作…

今まで、全く触れていませんでしたが…
でも、クラスは使っていますよね。

クラスって何だ?
簡単に言うと…
データと、そのデータを扱う関数を1つにまとめたもの。
詳しくはwikiを見てください。
継承だのメソッドだの、難しそうな事が書いてあります。

では、試してみましょう。

嘘を言ってるかもしれませんので、他のサイトや出版物も参考にしてください。

クラスとは、データとデータを扱う関数を1つにまとめた物。

では、ある変数a(データ)があり、この変数に有効範囲を設定したとします。
例えば、10.0~100.0までの数値を扱う変数だとします。
この変数aの値が、10.0未満や100.0超過だと不具合だとします。
そうすると、単純にif()を使って制限を掛けますよね。
入力させなかったり、強制的に値を限界値に変更したりと…

/*
テスト1
2009.7.29
*/


main(doc , op)
{
  var a;

  //変数aに入力
  a = 2.5;

  //変数aに制限を掛ける
  if(a < 10.0)
    a = 10.0;
  else if(a > 100.0)
      a = 100.0;

  //変数aの出力
  println(a);
}

そうすると、変数aに入力があるたびに制限を掛けるif()を書き込むわけだ…

/*
テスト2
2009.7.29
*/


main(doc , op)
{
  var a;

  //変数aに入力
  a = 2.5;

  //変数aに制限を掛ける
  if(a < 10.0)
    a = 10.0;
  else if(a > 100.0)
      a = 100.0;

  //変数aの出力
  println(a);




  //変数aに入力
  a = 112.5;

  //変数aに制限を掛ける
  if(a < 10.0)
    a = 10.0;
  else if(a > 100.0)
      a = 100.0;

  //変数aの出力
  println(a);
}

何度も使うのであれば、普通関数にするだろう…
なんだか、クラスの話じゃないなぁ…

/*
テスト3
2009.7.29
*/


InpurA(a)
{
  if(a < 10.0)
    a = 10.0;
  else if(a > 100.0)
      a = 100.0;

  return a;
}


main(doc , op)
{
  var a;

  //変数aに入力
  a = InputA(2.5);

  //変数aの出力
  println(a);


  //変数aに入力
  a = InputA(112.5);

  //変数aの出力
  println(a);
}

これで、変数aに制限を掛ける為に制限用関数(データを扱う関数)に数値を渡して、戻ってきた値を変数aに代入します。
でも、この状態だと、間違って直接変数aに代入する事もできますので、完全に変数aに制限した入力がしきれてません。
InputA()も単純な関数で変数aの入力制限の関数ではありますが、変数aとは一体にはなっていません。
これだと、変数が増えると、どの関数が、どの変数の為の数値を制御する関数なのかわかり辛くなりますね。

では、ここでクラスを使ってみます。

クラスの定義は…

class クラス名
{
  var メンバ変数名;
    :
    :

  クラス名(引数リスト);//クラスのコンストラクタ

  メンバ関数名(引数リスト);
    :
    :
}

変数と関数を必要なだけ定義してください。

続いて、クラスのコンストラクタ。このクラスを使うときにnew()で割り当てられると実行される関数。クラスの初期化等をする関数。
クラス名と同じ名前の関数にします。
ただクラスをnew()で割り当てられただけだと、メンバ変数はnilになっているので、初期値を入力するなり…

クラス名::クラス名(引数リスト)
{
  メンバ変数 = 初期値;
    :
    :
}

クラスの定義で記述した関数の定義を…

クラス名::メンバ関数名(引数リスト)
{
  //処理用コードを好きなように…
}

大雑把だけど…

では、先ほどのスクリプトにクラスを使用すると…

/*
テスト4
2009.7.29
*/


//クラスtest_aの定義
class test_a
{
  private:
    var a;

  public:
    test_a();
    InputA(val);
    OutputA();
}

test_a::test_a()//コンストラクタ
{
  a = 15.0;
}

test_a::InputA(val)//メンバ変数aの入力用メンバ関数
{
  if(val < 10.0)
    val = 10.0;
  else if(val > 100.0)
      val = 100.0;

  a = val;
}

test_a::OutputA()//メンバ変数aの出力用メンバ関数
{
  return a;
}





main(doc , op)
{
  var testclass = new(test_a);
  println("初期値:" , testclass->OutputA());

  //クラスtestclassに入力
  testclass->InputA(2.5);

  //クラスtestclassの出力
  println("入力1:" , testclass->OutputA());


  //クラスtestclassに入力
  testclass->InputA(112.5);

  //クラスtestclassの出力
  println("入力2:" , testclass->OutputA());
}

扱う変数や処理のわりに、クラスを使うと…
機能の割には、無駄に大きくなったような…

たかだか、変数1個の為にクラスを使うことは無いだろうか…

でも色んな場面で使って行くうちに、便利さに納得するだろう…
汎用性のあるクラスを書けば、使い回しができるので、新たにスクリプトを組むときにも、開発時間がかからずに済むだろうし…

上のスクリプトは実行してもエラーは起こらず、終了します。
コンソールには15.0、10.0と100.0を表示して…

クラスの定義で説明をしなかったprivate/public。
先ほどのスクリプトには無かったOutputA()ですね。

private/publicは、クラスのメンバー(関数や変数)へのアクセス権。

privateは、クラス内からはアクセスできるけど、クラス外からはアクセスができません。
これによって、上のスクリプトのtest_aクラスのメンバ変数aが、外部から勝手な数値の入力を防ぎます。
必ず、メンバ関数InputA()を使って入力しないと変更できません。

publicは、クラス内外関係なくアクセスができます。

OutputA()関数ですが、test_aクラスのメンバ変数aがprivateになっているため、値を直接取得できなくなります。
その為に、メンバ変数aにアクセスするメンバ関数が必要になります。

publicとprivateはイメージ的には、こんな感じだろうか?

Class_01

それでは、もっと簡単なクラスでテスト。

クラスの定義でpublic/private等を省略すると…

/*
クラスのメンバのアクセス権を省略すると
2009.7.29
*/


class test
{
  var v;
}

main(doc , op)
{
  var a = new(test);

  println(a->v);//testクラスのメンバ変数vへアクセス
}

[FAIL] Script 'xxxx' Line 15 : Member is not PUBLIC

エラーが出ました。
省略すると、public以外のものになります。

クラスのコンストラクタを省略したり、コンストラクタでメンバ変数を初期化しないと、メンバ変数は本当にnilになるのか?

/*
クラスのコンストラクタを省略するとメンバ変数の値は?
2009.7.29
*/


class test_A
{
  public:
    var v;
}

class test_B
{
  public:
    var v;
    test_B();
}

test_B::test_B()
{

}

main(doc , op)
{
  var a = new(test_A);
  var b = new(test_B);

  println(a->v);//test_Aクラスのメンバ変数vへアクセス
  println(b->v);//test_Bクラスのメンバ変数vへアクセス
}

nil
nil

本当にnilになりました。

クラスをnew()で宣言するときに、引数を渡して、メンバ変数の初期値にしたりするには?

/*
クラスの宣言で引数を渡す
2009.7.29
*/


class test
{
  public:
    var v;
    test(val);
}

test::test(val)
{
  v = val;
}

main(doc , op)
{
  var a = new(test , 10);//引数を渡す

  println(a->v);//testクラスのメンバ変数vへアクセス
}

10

問題なく、new()から渡す事ができました。

クラスの定義でコンストラクタを記述し、実際のコンストラクタを定義しないと?

/*
クラスの宣言でコンストラクタを記述し、コンストラクタを定義しないと?
2009.7.29
*/


class test
{
  public:
    var v;
    test();
}

main(doc , op)
{
  var a = new(test);

  println(a->v);//testクラスのメンバ変数vへアクセス
}

[FAIL] Script 'xxxx' Line 15 : is not a function -> NIL

エラーが起きているのは、クラスtestのコンストラクタを呼び出そうとしているnew()の所なのだろう…
関数では無いと言っている。NILだよ。
クラスの定義の部分ではエラーではなく、new()で呼び出しの所でエラー…

この事から、考えられる事は…
クラスの定義では、メンバーの数だけ確保して、全てにnilを…
クラスの定義後に、該当するメンバ関数の定義があったらなら関数を指し示す。それだけ…
メンバ関数の定義が無ければエラーではなくnilのまま…
呼び出されて初めてエラーが出る…
呼び出されなければメンバ関数が定義されていなくても永久的にエラーが出ない。

では、コンストラクタ以外のメンバー関数で試してみる。

/*
クラスの宣言で関数を記述したけど関数自体を定義しないと?
2009.7.29
*/

class test
{
  public:
    var v;
    func();
}

main(doc , op)
{
  var a = new(test);

  println(a->v);//testクラスのメンバ変数vへアクセス
}

nil

エラーは起こらず…

こうなると、大量にクラスを定義してメンバ関数の定義をわすれて…
実行されなければ、不具合を抱えたまま気付かない事になる。
デバッグ時に注意しないといけないかも…
でも、使われてないなら、無いに等しいのか…

忘れていましたが、クラスのメンバにアクセスするには…

クラス名->メンバ名;

次回に続く…

|

« C4D C.O.F.F.E.E.SDK GeModalDialogの頁の誤 | トップページ | C4D C.O.F.F.E.E. クラスを使うには…_02 »