「型変換」の版間の差分

削除された内容 追加された内容
編集の要約なし
編集の要約なし
4行目:
== 分類 ==
=== 暗黙の型変換と明示的型変換 ===
'''暗黙の型変換'''は、明示的に指定しなくても[[コンパイラ]]の判断によって自動的に行われる型変換である。逆に、明示的に指定して行う型変換を'''明示的型変換'''という。
 
暗黙の型変換では、たとえばある式の中に複数の型の変数がある場合、すべての変数を最も上位の型に変換する。
20行目:
この[[C言語]]のコードでは、<code>d</code>と<code>l</code>と<code>i</code>は異なったデータ型をもっているので、すべての演算は自動的に同じ型に変換された後に行われる。より大きなサイズの型に変換されることを拡大変換 (widening conversion) と呼び、より小さなサイズの型に変換されることを縮小変換 (narrowing conversion) と呼ぶ。
 
暗黙の型変換には注意しなければならないこともある。たとえば<code>double</code>型([[浮動小数点数]])の値を<code>int</code>型([[整数型]])の変数に代入する場合、小数点以下の端数があったり、元の値が<code>int</code>型で表現できる範囲を超えていたりすると、縮小変換により情報の一部が失われてしまう。C言語および[[C++]]では暗黙の縮小変換を許しているが、情報が失われる可能性のある変換に対して、通例[[コンパイラ]]が警告を出す。[[Java]]や[[C Sharp|C#]]などの後発言語では、暗黙の縮小変換を許可せず、後述するキャスト (cast) 構文による明示的な変換が必要となる。さらに型の扱いが厳密な[[F Sharp|F#]]などの関数型言語では、暗黙の拡大変換も許可せず、キャスト構文による明示的な型変換が必要となる。
 
===組込みの型変換とユーザ定義の型変換===
基本的な型変換(整数どうしの変換や、整数と浮動小数点数との間の変換など)は、多くのプログラミング言語処理系でコンパイラまたは最初から定義されており、通例[[プロセッサ]] ([[CPU]]) よってサポートされる高速なハードウェア変換命令定義コンパイルされている。一方、ある型から別の型への変換をユーザが定義できる言語もある。
 
例えば[[C++]]では、ユーザ定義型の中に変換元の型を一つだけとる引数付き[[コンストラクタ]]を定義すれば、ユーザ定義の暗黙の型変換が定義できる。これを変換コンストラクタ (converting constructor) と呼ぶ。コンストラクタに<ttcode>explicit</ttcode>修飾子をつけると暗黙の型変換が許されなくなり、明示的型変換が必要となる。
 
<source lang="cpp">
31行目:
class Class2 {
public:
explicit Class2(Class1 c1) { /* ... */ }
};
 
void test() {
Class1 c1;
Class2 c2 = (Class2)c1;
// explicit 修飾子がなければ Class2 c2 = c1; でよい
// explicit の有無にかかわらず、Class2 c2(c1); と書くことは常にできる。
}
</source>
 
ここで、<ttcode>Class1</ttcode>と<ttcode>Class2</ttcode>の間には継承関係がないにもかかわらず代入ができている。これは<ttcode>Class1</ttcode>からコンストラクタを通して<ttcode>Class2</ttcode>に型変換されるからである。
 
なお、上の例では型変換の構文をとってはいるが、実際の処理としては<code>c1</code>はコンストラクタへの引数として渡されている。そのため、本来必要のない<code>c1</code>のコピーが生成される。これを避けるために、変換元の型がユーザ定義型である場合には、通常は引数を[[参照 (情報工学)|参照]]として渡す。また、型変換という操作の意味を考えれば、変換元のインスタンスに変更を加えるということはあり得ないので、通常は引数に<code>const</code>修飾子をつけて変更不可とする。結局、コンストラクタの宣言は<code>explicit Class2(const Class1& c1) { ... }</code> のように書くことが多い。
 
なお、[[C++11]]以降では複数の引数を持つコンストラクタであっても、<code>explicit</code>を指定しない場合は変換コンストラクタとなることができる<ref>[https://ja.cppreference.com/w/cpp/language/explicit explicit 指定子 - cppreference.com]</ref>。
なお、上の例では型変換の構文をとってはいるが、実際の処理としては<code>c1</code>はコンストラクタへの引数として渡されている。そのため、本来必要のない<code>c1</code>のコピーが生成される。これを避けるために、変換元の型がユーザ定義型である場合には、通常は引数を[[参照 (情報工学)|参照]]として渡す。また、型変換という操作の意味を考えれば、変換元のインスタンスに変更を加えるということはあり得ないので、通常は引数に<code>const</code>修飾子をつけて変更不可とする。結局、コンストラクタの宣言は<code>explicit Class2(const Class1& c1) { ... }</code> のように書くことが多い。
 
=== キャストとその分類 ===
71 ⟶ 74行目:
またC# 7.0では、<code>is</code>演算子が拡張され、変換可能性を[[ブーリアン型|bool型]]で返すと同時に、末尾で宣言した変数に変換結果が格納される
<ref>https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/is</ref>。
<code>as</code>演算子<code>is</code>演算子共に、通常のキャスト演算子とは異なり、ユーザ定義変換は行われない。
 
==== クロスキャスト ====