aliasとwith
alias
aliasキーワードは、既存の名前に対して別名を割り当てる。aliasは、alias thisとは別のものであり、関連もない。
長い名前を短縮する
前の章で見たように、名前が長すぎて使いにくい場合がある。その章で見た次の関数を考えてみよう。
プログラム内の複数の場所でStack!(Point!double)を明示的に入力しなければならないことには、いくつかの欠点がある。
- 長い名前はコードを読みづらくする可能性がある。
- 型が、
Point構造体テンプレートのdoubleインスタンスのオブジェクトを含むStackデータ構造であることを、すべての箇所で意識する必要がある。 - プログラムの要件が変更され、例えば
doubleをrealに変更する必要が生じた場合、この変更は複数の場所で実施する必要がある。
これらの欠点を解消するには、Stack!(Point!double)に新しい名前を付ける。
さらに進んで、一方をもう一方の利点を利用するように2つのエイリアスを定義することも考えられる:
aliasの構文は次の通りだ:
この定義後、新しい名前と既存の名前は同義語になる:プログラム内では同じ意味を持つ。
この機能の古い構文が一部のプログラムで遭遇する可能性がある:
// 古い構文の使用は避けてください:
alias existing_name new_name;
aliasは、モジュール名とともに完全に記述しなければならない名前を短縮する場合にも便利だ。Queenという名前が2つの別々のモジュール、chessとpalaceに登場するとしよう。両方のモジュールがインポートされている場合、Queenとだけ入力すると、コンパイルエラーが発生する。
コンパイラは、どのQueenが意図されたものかを判断できない:
この衝突を解決する便利な方法は、1つ以上の名前に対してエイリアスを割り当てることだ:
alias他の名前でも動作する。次のコードは変数に新しい名前を割り当てる:
設計の柔軟性
柔軟性を高めるため、intのような基本的な型にもエイリアスを付けることができる。
この構造体のユーザーが、intおよびstringの代わりに、常にCustomerNumberおよびCompanyNameと入力する場合、ユーザーコードに影響を与えることなく、将来、設計をある程度変更することができる。
これは、コードの可読性にも役立つ。変数の型をCustomerNumberと指定すると、intよりもその変数の意味に関するより多くの情報が伝わる。
このような型エイリアスは、構造体やクラス内で定義され、それらの型のインターフェースの一部になることがある。次のクラスには、weightプロパティがある。
そのクラスのメンバー変数とプロパティはdoubleとして定義されているため、ユーザーはdoubleも使用する必要がある。
weightの型がaliasとして定義されている別の設計と比較しよう。
この場合、ユーザーコードでは通常、Weightも使用される:
この設計では、将来Weightの実際の型を変更しても、ユーザーコードには影響がない。(つまり、新しい型も+=演算子をサポートしている場合。)
スーパークラスの隠れた名前の公開
スーパークラスとサブクラスで同じ名前が使用されている場合、スーパークラスにある一致する名前は隠蔽される。サブクラスにその名前が1つでも存在すれば、スーパークラスにあるその名前と一致するすべての名前が隠蔽される:
引数は42であるため、int値であるため、intを受け取るSuper.foo関数がその用途のために呼び出されることを予想するかもしれない。しかし、パラメータリストは異なるものの、Sub.fooは Super.fooを隠蔽し、コンパイルエラーが発生する。コンパイラはSuper.fooを完全に無視し、Sub.fooはintによって呼び出せないことを報告する。
これは、スーパークラスの関数をオーバーライドすることとは異なることに注意。オーバーライドの場合、関数のシグネチャは同じになり、overrideキーワードによって関数がオーバーライドされる。(overrideキーワードについては、継承の章で説明した。)
ここでは、オーバーライドではなく、名前隠蔽と呼ばれる言語機能が有効になっている。名前隠蔽がない場合、これらのクラスに追加または削除された、たまたま同じ名前fooを持つ関数は、呼び出される関数を黙って変更してしまうかもしれない。名前隠蔽は、このような予期せぬ動作を防ぐ。これは他の OOP 言語にもある機能だ。
alias 必要に応じて隠された名前を明らかにできる:
上記のaliasは、スーパークラスのfooの名前をサブクラスのインターフェースに持ち込む。その結果、コードはコンパイル可能になり、Super.fooが呼び出されるようになる。
必要に応じて、異なる名前で名前をサブクラスに持ち込むこともできる:
名前隠蔽はメンバー変数にも影響する。aliasは、それらの名前もサブクラスのインターフェースに持ち込むことができる:
一方がメンバー変数で、もう一方がメンバー関数であるかどうかに関係なく、サブクラスの名前cityは、スーパークラスの名前cityを隠す。
同様に、スーパークラスのメンバー変数の名前は、aliasを使用してサブクラスのインターフェースに持ち込むことができる。必要に応じて異なる名前で:
with
withは、オブジェクトまたはシンボルへの繰り返し参照を削除するためのものである。括弧で囲まれた式またはシンボルを取り、withのスコープ内で使用される他のシンボルを検索する際にその式またはシンボルを使用する。
括弧内に一時オブジェクトを作成することもできる。その場合、一時オブジェクトはl値となり、その有効期間はスコープを離れると終了する。
後でポインタの章で見るように、newキーワードを使用して一時的なオブジェクトを構築することができ、その場合、そのオブジェクトの寿命はスコープを超えて延長される。
withは、enum型などの繰り返し参照を削除するために、caseセクションで特に役立つ。
要約
alias既存の名前に対して別名(エイリアス)を割り当てる。with同じオブジェクトまたはシンボルへの繰り返し参照を削除する。