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
同じオブジェクトまたはシンボルへの繰り返し参照を削除する。