スーパークラスのフィールドへのアクセス

読書会で、抽象クラスのフィールドはデフォルトで

  • protectedにする
  • privateにしてprotectedなgetter/setter*1を用意する

のどちらがいいか、という話があった。


昔は後者を好んで使用していたけど、最近はとりあえず前者を使うことが多い。なんたって手軽だし。


で、前者の問題として、そのフィールドが何者か分かりにくい、という点があげられる。
これの解決方法として、スーパークラスのフィールドにアクセスする際には、明示的にsuper*2をつけてアクセスするという方法を採用している。


例えば、

// Java版
abstract class Hoge {
    protected int i;
}

final class HogeImpl extends Hoge {
    void method() {
        System.out.println(super.i);
    }
}
// C#版
internal abstract class Hoge
{
    protected int i;
}

internal sealed class HogeImpl : Hoge
{
    internal void Method()
    {
        System.Console.WriteLine(base.i);
    }
}
// C++版
class hoge
{
protected:
    virtual ~hoge() = 0;
    int i;
    
    typedef hoge inherited;
};

struct hoge_impl : public hoge
{
    ~hoge_impl() {}
    void func()
    {
        std::cout << inherited::i << std::endl;
    }
};

みたいに。


この方法の欠点は、強制することが困難というところかな。


ちなみにthisについては、昔はほとんどに付けていたけど、最近では最低限必要な部分*3にしか付けていない。
これは単に好みが変化したから。だって面倒ジャン。

*1:setterは必要あれば

*2:Javaでは、ね

*3:引数の変数名とフィールド名がかぶる場合、例えばコンストラクタ内部とか。ローカル変数では型を省略した名前などを使い、フィールド名と重複しないようにしている