Top > Shiba > Shiba Language > ユーザー定義型

* ユーザー定義型 [#u10b9718]
#contents

* 概要 [#k79548b7]

|項目|pod|struct|class|interface|utility|h
|デフォルトコンストラクタのユーザー定義|x *1|x *1|o|x|x|
|コンストラクタ|o|o|o|x|x|
|デストラクタ|x|o|o|x|x|
|静的コンストラクタ&br;静的デストラクタ|o|o|o|x|o|
|メンバ変数|o|o|o|x|x|
|structメンバ変数|x|o|o|x|x|
|objectメンバ変数|x|o|o|x|x|
|メンバ関数|o|o|o|o|x|
|ガベージコレクタ対象|x|x|o|o|x|
|インターフェースの継承|x|x|o|o|x|
|公開修飾子(public/private)|o|o|o|x|o|
|代入オーバーロード|x|o|x|x|x|
|>|>|>|>|>|ver2.0|
|invariant|o|o|o|x|x|
|scope属性|x|x|o|x|x|
|inlineメンバ変数|o|o|o|x|x|

*1 : 全部0(規定値)で初期化。
structでも許さない理由は,static変数にstructな変数を定義すると,初期化時に関数コールが走ってしまうため。
関数コールは.init初期化が終わった後から呼び出すように統一したい。
** interface [#s160dc18]
- C#,Dのinterfaceと同じ
- interfaceは複数にinterfaceを継承することができる

#code(c,){{
interface IButtonListener
{
    // 継承したクラスは必ず実装する必要がある。
    void onButtonPush( in IButton sender )const;
};
}}
** class [#gcd95ad1]
- 強制的にobject型を継承している
- DやC#のように1つだけの継承できるはできる。多重継承はできない。
- interfaceは何個でも継承できる
** pod [#y7b8ef47]
- plain object data
- C言語のstructに近い
- デフォルトコンストラクタはオブジェクトのメモリ領域を0で初期化する扱いになる

** struct [#g20f0c14]
- 継承のないC++のクラス・D言語のscope classと同じ
- ガベージコレクト対象ではないので,structなオブジェクトをnewしそのインスタンスの参照を保持することができない
** utility [#maa1e0a9]
- static関数のみ提供する型,インスタンスを作ることができない。


* メンバ公開修飾子 - public private(class,struct) [#f2079e32]
- protectedは無い。
- デフォルトはpublic
- コロンを使うC++スタイル、メンバ変数・関数に直接記述するJAVAスタイルの両方に対応

#code(c,){{
class A
{
    //--- 公開修飾子(デフォルトpublic)
    // C++/Dスタイル
public: 
    void funcPubA(){} // public
private:
    void funcPriA(){} // private

    // JAVA/C#/Dスタイル
    public void funcPubB(){} // public
    private void funcPriB(){} // private

};

}}
* オーバーライドチェック - override(class) [#a382e838]
- D,C#と同じ
* 不変条件 - invariant(class,pod,struct) [#h6f6ff79]
- (all)Dのinvariantとほぼ同じ
-- 呼び出されるタイミング
--- publicなメンバ関数の実行直前・直後
--- publicメンバ変数にアクセスする直前・直後
--- コンストラクタの直後
--- デストラクタの直前
-- invariant関数内でpure constメンバ関数以外のメンバ関数を呼び出すことを禁止。
- <要検討>structで再帰呼び出しされたらどうしよう(classはカウンタ持たせればいいかな)
-- ↑これってどういう意味だっけ;
* 委譲 (class) [#ga454cd5]
- interfaceのデフォルト実装を別オブジェクトに委譲する

#code(c,){{
interface IButtonListener
{
    abstract void onPushed();
    void onFocused(){}
};
class Hoge : IButtonListener
{
public:
    override void onPushed(){}
};

class A : IButtonListener = mHoge
{
    // IButtonListenerの関数を全てmHogeに委譲される
    // implementを使うと自動で次のように展開される
    // override void onPushed(){ mHoge.onPushed(); }
    // override void onFocused(){ mHoge.onFocused(); }
private:
    Hoge@ mHoge;
};

class B : public IButtonListener = mHoge
{
    // onFocusedの関数だけ実装、その他はmHogeにまかせる
    override void onFocused() { /* */ }
private:
    Hoge@ mHoge;
};

}}
* コンストラクタ - this() (class,pod,struct) [#ta13d165]
- (all)D言語の形式を採用し、関数名はthisを使う
- (all)別コンストラクタ関数コールは可能
- (all)どのコンストラクタよりも前に.Initデータをメモリ領域にセットされる(D言語と同じふるまいをする)
- (pod)デフォルトコンストラクタは定義できない(0初期化固定)
- (struct,pod)デフォルトコンストラクタは定義できない(0初期化固定)
#code(c,){{
class A
{
public:
    this()
    {
      mY = mX + 1;
    } 
    this(in int x, in int y)
      : this()
    {
      mX = x;
      mY = y;
    }

    int mX = 1; // 直接初期化子を書くことが出来る。ただし,コンパイル時に決まる定数しか書けない。
    int mX = 1; // 直接初期化子を書くことが出来る。ただし,コンパイル・リンク時に決まる定数しか書けない。
    int mY; // 指定がないとデフォルトコンストラクタが呼ばれる。
};
}}
* デストラクタ - ~this() (class,struct) [#p2eecfc4]
- D言語スタイルを採用

#code(){{
class A
{
public:
    ~this()
    {
    }
};
}}

* 静的コンストラクタ - static this() (class,struct,pod,utility) [#o27052fb]
- D言語と同じ
- 静的コンストラクタが呼ばれる前に,.initデータがメモリ領域にコピーされる。

#code(){{
class A
{
    static int hoge = 1;
    static int foo; // hoge * 2を代入したいが,他の変数を参照することができない
    
    static this()
    {
        // この時点で,.initデータがコピー済み。
        // つまり,hogeには1,fooには0(デフォルト値)が代入済み

        foo = hoge * 2; // ここなら他の変数を参照することができる。
    }
};
}}
* 静的デストラクタ - static ~this() (class,struct,pod,utility) [#cd758315]
- D言語と同じ

#code(){{
class A
{
    static ~this()
    {
    }
};
}}
* 静的メンバ関数 (class,interface,pod,struct,utility) [#ta1939b9]
- D言語と同じ。

* 静的メンバ変数 (class,pod,struct) [#u1b23ba6]
- D言語と同じ。

* メンバ関数 (class,interface,struct,pod) [#l90075b8]
- (all)C++でいうメンバ関数のconst修飾子はあり。引数リストの括弧の後ろにconstを付ける。
- (class)抽象関数にoverrideキーワードが使える
- (interface)純粋仮装関数には先頭にabstractキーワードを付ける
- (interface)デフォルト実装はstatic関数として同じ名前の関数が定義される。
- (class)抽象関数にoverrideキーワードが使え,ちゃんと継承できていなければコンパイルエラーになる。

#code(c,){{
interface IName
{
  string getName(){ return "NoName"; }
  // こう書くと自動でstatic関数が作られる
  // static string getName() { return "NoName"; }
  // IName.DEFAULT.getName( IName )でアクセスできる
};
}}

* メンバ変数 (class,struct,pod) [#xe0c9c25]
- publicなメンバ変数は関数に展開される。
- こうすることで変数のオフセット情報を知る必要がなくなり,再コンパイルの回数を減らすことができる。
#code(c,){{
struct Hoge
{
  public int a;
  // これは下記のように展開される
  // public ref int __mv_ref_a()
  // {
  //   return a;
  // }
  // public const ref int __mv_ref_a()const
  // {
  //   return a;
  // }

  static void test()
  {
    Hoge h;
    h.a = 3; // h.__mv_ref_a() = 3; に展開される

    h.a = Hoge().a + Hoge().a;
    // 展開後
    // {
    //   Hoge __tv00;
    //   Hoge __tv01;
    //   h.__mv_ref_a() = __tv00.__mv_ref_a() + __tv01.__mv_ref_a();
    // }

    h.a += 3;
    // 展開後
    // h.__mv_ref_a() += 3;
  }
}
}}
** inlineメンバ変数 [#rb185fd4]
#code(c,){{
class Hoge
{
  public inline Foo@ a;
  // こうするとメンバ変数にダイレクトにアクセスするようになる。
  // invariantメソッドが実装されていても呼ばれなくなる。
  // Fooのメンバ変数の構成が変更されると再コンパイルが必要になる。
};


}}


    ホーム 一覧 検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS