ハンドル クラスと値クラスの比較
基本的な違い
"value" クラス コンストラクターは、代入先の変数に関連付けられたオブジェクトを返します。この変数を代入し直すと、MATLAB® は元のオブジェクトの独立したコピーを作成します。この変数を変更するために関数に渡す場合、関数は変更されたオブジェクトを出力引数として返さなければなりません。値クラスの動作については、データの不要なコピーの回避を参照してください。
handle クラス コンストラクターは、作成されたオブジェクトへの参照であるハンドル オブジェクトを返します。MATLAB にオリジナル オブジェクトのコピーを作成させないで、ハンドル オブジェクトを複数の変数に割り当てたり、あるいはそれを関数に渡したりすることができます。入力引数として渡されたハンドル オブジェクトを変更する関数は、そのオブジェクトを返す必要がありません。
すべてのハンドル クラスは抽象クラス handle から派生します。
値クラスの作成
既定では、MATLAB クラスは値クラスです。以下の定義は MyValueClass という名前の値クラスを作成します。
classdef MyValueClass ... end
ハンドル クラスの作成
handle クラスを作成するには、handle クラスからクラスを派生させます。
classdef MyHandleClass < handle ... end
MATLAB 組み込みクラスの動作
MATLAB の基本クラスは値クラスです (数値、logical、char、cell、struct、および関数ハンドル)。たとえば、int32 クラスのオブジェクトを作成し、このオブジェクトのコピーを作成すると、結果として 2 つの独立したオブジェクトになります。a の値を変更しても b の値は変わりません。これは値を表すクラスの通常の動作です。
a = int32(7); b = a; a = a^4; b
b = int32 7
MATLAB グラフィックス オブジェクトは視覚的要素を表すため、ハンドル オブジェクトとして実装されます。たとえば、グラフィックスの line オブジェクトを作成し、そのハンドルを他の変数にコピーします。両方の変数が同じ line オブジェクトを参照します。
x = 1:10; y = sin(x); l1 = line(x,y); l2 = l1;
ハンドルのコピーのいずれかを使用して、line オブジェクトのプロパティを設定します。
set(l2,'Color','red') set(l1,'Color','green')
get(l2,'Color')ans =
0 1 0l2 ハンドルに対して関数 delete を呼び出すと line オブジェクトは破棄されます。line l1 に Color プロパティを設定しようとすると、関数 set はエラーを返します。
delete(l2) set(l1,'Color','blue')
Error using matlab.graphics.primitive.Line/set Invalid or deleted object.
既存ハンドルの削除によってこのオブジェクトを削除すると、すべてのコピーが無効になります。これは、すべてのハンドルが参照する唯一のオブジェクトを削除したためです。
ハンドル オブジェクトの削除はハンドル変数のクリアと同じではありません。グラフィックス オブジェクト階層では、オブジェクトの親がオブジェクトへの参照を保持します。たとえば、親座標軸は、l1 と l2 によって参照される line オブジェクトへの参照を保持します。ワークスペースから両方の変数をクリアしても、オブジェクトは存在したままです。
ハンドル オブジェクトの動作の詳細については、ハンドル オブジェクトの動作を参照してください。
ユーザー定義の値クラス
MATLAB は、値クラスのオブジェクトをオブジェクトの代入先の変数に関連付けます。値オブジェクトを別の変数にコピーするか、または値オブジェクトを関数に渡すと、MATLAB はオブジェクトとオブジェクトに含まれるすべてのデータの独立したコピーを作成します。新しいオブジェクトは、元のオブジェクトに加えられた変更内容には影響されません。値オブジェクトは MATLAB の数値クラスと struct クラスのように動作します。各プロパティは、本質的に MATLAB 配列のように動作します。
値オブジェクトは、常に 1 つのワークスペースまたは一時変数に関連付けられています。値オブジェクトの変数がスコープ外になるかクリアされると、値オブジェクトはスコープ外になります。値オブジェクトへの参照は存在せず、独立したオブジェクトのコピーのみが存在します。
値オブジェクトの動作
Number プロパティに値を格納する値クラスを次に示します。既定のプロパティ値は数値 1 です。
classdef NumValue properties Number = 1 end end
変数 a に代入する NumValue オブジェクトを作成します。
a = NumValue
a =
NumValue with properties:
Number: 1a の値を別の変数 b に代入します。
b = a
b =
NumValue with properties:
Number: 1変数 a と変数 b は独立しています。a の Number プロパティの値を変更しても、b の Number プロパティには影響しません。
a.Number = 7
a =
NumValue with properties:
Number: 7b
b =
NumValue with properties:
Number: 1関数内の値オブジェクトの変更
値オブジェクトを関数に渡すと、MATLAB はそのオブジェクトのコピーを関数のワークスペース内に作成します。値オブジェクトのコピーは独立しているため、関数は呼び出し元のワークスペースにあるオブジェクトを変更しません。このため、値オブジェクトを変更する関数は、呼び出し元のワークスペースで代入し直すために、変更されたオブジェクトを返さなければなりません。
詳細については、オブジェクトの変更を参照してください。
ユーザー定義のハンドル クラス
handle クラスから派生するクラスのインスタンスは、基となるオブジェクト データの参照です。ハンドル オブジェクトがコピーされると、MATLAB によってそのハンドルがコピーされますが、オブジェクト プロパティに保存されたデータはコピーされません。コピーは、元のハンドルと同じオブジェクトを参照します。元のオブジェクトのプロパティ値を変更すると、コピーされたハンドルは同じ変更内容を参照します。
ハンドル オブジェクトの動作
Number プロパティの値を格納するハンドル クラスを以下に示します。既定のプロパティ値は数値 1 です。
classdef NumHandle < handle properties Number = 1 end end
変数 a に代入する NumHandle オブジェクトを作成します。
a = NumHandle
a =
NumHandle with properties:
Number: 1a の値を別の変数 b に代入します。
b = a
b =
NumHandle with properties:
Number: 1変数 a および変数 b は、基となる同じオブジェクトを参照します。a の Number プロパティの値を変更すると、b の Number プロパティも変わります。つまり、a と b は同じオブジェクトを参照しています。
a.Number = 7
a =
NumHandle with properties:
Number: 7b
b =
NumHandle with properties:
Number: 7関数内のハンドル オブジェクトの変更
ハンドル オブジェクトを関数に渡すと、MATLAB はそのハンドルのコピーを関数のワークスペース内に作成します。ハンドルのコピーが基となる同じオブジェクトを参照するため、ハンドル オブジェクトを変更する関数は呼び出し元のワークスペースにあるオブジェクトも事実上変更します。したがって、入力引数として渡されたハンドル オブジェクトを変更する関数は、変更されたオブジェクトを呼び出し元に返す必要はありません。
詳細については、オブジェクトの変更を参照してください。
ハンドルの削除
ハンドルの delete メソッドを明示的に呼び出して、ハンドル オブジェクトを破棄できます。ハンドル クラス オブジェクトのハンドルを削除すると、すべてのハンドルが無効になります。以下に例を示します。
a = NumHandle; b = a; delete(a) b.Number
Invalid or deleted object.
ハンドル オブジェクトで delete を呼び出すと、そのオブジェクトのデストラクター関数が起動します。詳細については、ハンドル クラスのデストラクターを参照してください。
ハンドル オブジェクトを含めるためのプロパティの初期化
properties ブロック内の既定値へのプロパティの初期化と、コンストラクター内からのプロパティの初期化との違いに関する詳細については、プロパティ値の初期化とオブジェクト配列の作成と初期化を参照してください。
オブジェクトの等価性の判定
値オブジェクトの等価性とは、オブジェクトが同じクラスのものであり、同じ状態をもつことを意味します。
ハンドル オブジェクトの等価性とは、ハンドル変数が同じオブジェクトを参照することを意味します。同じ状態をもつ同じクラスの異なるオブジェクトを参照するハンドル変数を識別することもできます。
値オブジェクトの等価性
値オブジェクトのサイズが同じで値が等しいかどうかを判定するには、isequal を使用します。たとえば、前に定義した NumValue クラスを使用して、2 つのインスタンスを作成して等価性をテストするには、次のようにします。
a = NumValue; b = NumValue; isequal(a,b)
ans =
1a と b は独立しているので同じオブジェクトではありません。ただし、それぞれが同じ値を示します。
値オブジェクトによって示される値を変更すると、オブジェクトは等価ではなくなります。
a = NumValue; b = NumValue; b.Number = 7; isequal(a,b)
ans =
0値クラスには、== 演算を実装する既定の eq メソッドはありません。
ハンドル オブジェクトの等価性
ハンドル オブジェクトは、handle 基底クラスから eq メソッドを継承します。== と isequal を使用して、ハンドル オブジェクト間の異なる 2 つの関係を次のようにテストできます。
ハンドルが同じオブジェクトを参照する場合、
==とisequalはtrueを返す。ハンドルが同じ値をもつ同じクラスのオブジェクトを参照するが、同じオブジェクトではない場合、
isequalのみがtrueを返す。
前に定義した NumHandle クラスを使用して、オブジェクトを作成してハンドルをコピーします。
a = NumHandle; b = a;
== と isequal を使用して等価性をテストします。
a == b
ans =
1isequal(a,b)
ans =
1既定値を使用して NumHandle クラスの 2 つのインスタンスを作成します。
a = NumHandle; b = NumHandle;
a と b が同じオブジェクトを参照するかどうかを判定します。
a == b
ans =
0a と b が同じ値をもつかどうかを判定します。
isequal(a,b)
ans =
1ハンドル クラスによってサポートされる機能
handle クラスからの派生により、クラスは以下を行うことができます。
複数の有用なメソッドを継承する (ハンドル クラスのメソッド)
イベントとリスナーを定義する (イベントとリスナーの構文)
動的プロパティを定義する (動的プロパティ — インスタンスへのプロパティの追加)
set メソッドと get メソッドを実装する (プロパティの Set/Get インターフェイスの実装)
コピーの動作をカスタマイズする (ハンドル クラスのコピーの実装)
弱い参照 (Weak Reference Handles) (R2024b 以降)
ハンドル クラスとそのメソッドの詳細については、ハンドル スーパークラスを参照してください。