サーチ…


クラスの定義

クラスは、クラスと同じ名前の.mファイル内のclassdefを使用して定義することができます。このファイルには、クラスメソッド内で使用するclassdef ... endブロックとローカル関数を含めることができます。

最も一般的なMATLABクラス定義の構造は次のとおりです。

classdef (ClassAttribute = expression, ...) ClassName < ParentClass1 & ParentClass2 & ...

   properties (PropertyAttributes) 
      PropertyName
   end 

   methods (MethodAttributes) 
      function obj = methodName(obj,arg2,...)
         ...
      end
   end

   events (EventAttributes) 
      EventName
   end

   enumeration
      EnumName
   end

end

MATLABドキュメンテーション: クラス属性プロパティ属性メソッド属性イベント属性列挙クラスの制限

例のクラス:

CarというクラスはCar.mファイルでCar.mように定義できます。

classdef Car < handle % handle class so properties persist
    properties
        make
        model
        mileage = 0;
    end

    methods
        function obj = Car(make, model)
            obj.make = make;
            obj.model = model;
        end
        function drive(obj, milesDriven)
            obj.mileage = obj.mileage + milesDriven;
        end
    end
end

コンストラクタは、クラスと同じ名前のメソッドであることに注意してください。 <コンストラクタは、その型のオブジェクトを初期化するオブジェクト指向プログラミングのクラスまたは構造の特別なメソッドです。コンストラクタは、通常、クラスと同じ名前を持つインスタンスメソッドであり、オブジェクトのメンバーの値をデフォルトまたはユーザ定義の値に設定するために使用できます。

このクラスのインスタンスは、コンストラクタを呼び出して作成できます。

>> myCar = Car('Ford', 'Mustang'); //creating an instance of car class 

driveメソッドを呼び出すと、走行距離が増えます

>> myCar.mileage 
    
    ans = 
            0

>> myCar.drive(450);

>> myCar.mileage
    
   ans = 
            450

値とハンドルクラス

MATLABのクラスは、値クラスとハンドルクラスという2つの主要なカテゴリに分類されます。主な相違点は、値クラスのインスタンスをコピーすると、元のデータが新しいインスタンスにコピーされ、ハンドルクラスの場合は新しいインスタンスが元のデータを指し、新しいインスタンスの値を変更すると元のデータに変更されます。クラスはhandleクラスから継承してhandleとして定義することができます。

classdef valueClass
    properties
        data
    end
end

そして

classdef handleClass < handle
    properties
        data
    end
end

次に

>> v1 = valueClass;
>> v1.data = 5;
>> v2 = v1;
>> v2.data = 7;
>> v1.data
ans =
     5

>> h1 = handleClass;
>> h1.data = 5;
>> h2 = h1;
>> h2.data = 7;
>> h1.data
ans =
     7

クラスと抽象クラスから継承

免責事項:ここに示した例は、抽象クラスと継承の使用を示すためのものであり、必ずしも実用的ではありません。また、MATLABではポリモーフィックなものがないので、抽象クラスの使用は制限されています。この例は、誰がクラスを作成し、別のクラスから継承し、共通クラスを定義するために抽象クラスを適用するかを示します。

抽象クラスの使用は、MATLABではかなり制限されていますが、それでも数回で有用になることがあります。

メッセージロガーが必要だとしましょう。以下のようなクラスを作成するかもしれません:

classdef ScreenLogger
    properties(Access=protected)
        scrh;
    end
    
    methods
        function obj = ScreenLogger(screenhandler)
            obj.scrh = screenhandler;
        end
        
        function LogMessage(obj, varargin)
            if ~isempty(varargin)
                varargin{1} = num2str(varargin{1});
                fprintf(obj.scrh, '%s\n', sprintf(varargin{:}));
            end
        end
    end
end

プロパティとメソッド

要するに、プロパティはオブジェクトの状態を保持し、メソッドはインタフェースのようなものであり、オブジェクトに対するアクションを定義します。

プロパティscrhは保護されています。このため、コンストラクタで初期化する必要があります。このプロパティにアクセスする他のメソッド(getter)がありますが、この例の対処法はありません。プロパティとメソッドは、ドット記法とそれに続くメソッドまたはプロパティの名前を使用して、オブジェクトへの参照を保持する変数を介してアクセスできます。

mylogger = ScreenLogger(1);                         % OK
mylogger.LogMessage('My %s %d message', 'very', 1); % OK
mylogger.scrh = 2;                                  % ERROR!!! Access denied

プロパティとメソッドはpublic、private、protectedのいずれかです。この場合、protectedは、継承されたクラスからscrhにアクセスできますが、 scrhからはアクセスできないことを意味します。デフォルトでは、すべてのプロパティとメソッドは公開されています。したがって、 LogMessage()はクラス定義の外部で自由に使用できます。また、 LogMessageは、オブジェクトがカスタムメッセージをログに記録するときに呼び出さなければならないことを意味するインタフェースを定義します。

応用

私が私のロガーを利用するスクリプトがあるとしましょう:

clc;
% ... a code
logger = ScreenLogger(1);
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');

同じロガーを使用する複数の場所があり、ファイルにメッセージを書き込むなど、より洗練されたものに変更したい場合は、別のオブジェクトを作成する必要があります。

classdef DeepLogger
    properties(SetAccess=protected)
        FileName
    end
    methods
        function obj = DeepLogger(filename)
            obj.FileName = filename;
        end
        
        function LogMessage(obj, varargin)
            if ~isempty(varargin)
                varargin{1} = num2str(varargin{1});
                fid = fopen(obj.fullfname, 'a+t');
                fprintf(fid, '%s\n', sprintf(varargin{:}));
                fclose(fid);
            end
        end
    end 
end

1行のコードを次のように変更してください:

clc;
% ... a code
logger = DeepLogger('mymessages.log');

上記の方法は単にファイルを開き、ファイルの最後にメッセージを追加して閉じます。現時点では、私のインターフェースと一貫性を持たせるために、メソッドの名前はLogMessage()であることを忘れないでください。 MATLABは抽象クラスを使用することにより、developperを同じ名前に固執させることができます。任意のロガーの共通インターフェースを定義するとしましょう:

classdef MessageLogger
    methods(Abstract=true)
        LogMessage(obj, varargin);
    end
end

このクラスからScreenLoggerDeepLogger両方を継承すると、 LogMessage()が定義されていないと、MATLABはエラーを生成します。抽象クラスは、同じインタフェースを使用できる類似のクラスを構築するのに役立ちます。

この例のために、私は若干異なる変更を行います。 DeepLo​​ggerは画面上とファイル内に同時にログメッセージを記録すると仮定します。のでScreenLoggerすでに画面上にログメッセージを、私は継承するつもりですDeepLoggerからScreenLoggger繰り返しを避けるために。 ScreenLoggerは最初の行から離れても全く変更されません:

classdef ScreenLogger < MessageLogger
// the rest of previous code 

ただし、 DeepLoggerではLogMessageメソッドの変更がさらに必要になります。

classdef DeepLogger < MessageLogger & ScreenLogger
    properties(SetAccess=protected)
        FileName
        Path
    end
    methods
        function obj = DeepLogger(screenhandler, filename)
            [path,filen,ext] = fileparts(filename);
            obj.FileName = [filen ext];
            pbj.Path     = pathn;
            obj = obj@ScreenLogger(screenhandler);
        end
        function LogMessage(obj, varargin)
            if ~isempty(varargin)
                varargin{1} = num2str(varargin{1});
                LogMessage@ScreenLogger(obj, varargin{:});
                fid = fopen(obj.fullfname, 'a+t');
                fprintf(fid, '%s\n', sprintf(varargin{:}));
                fclose(fid);
            end
        end
    end
end

まず、コンストラクタのプロパティを初期化するだけです。第2に、このクラスはScreenLoggerから継承するので、私はこのパラレルオブジェクトも初期化する必要があります。 ScreenLoggerコンストラクターは独自のオブジェクトを初期化するために1つのパラメーターを必要とするため、この行はさらに重要です。この行:

obj = obj@ScreenLogger(screenhandler);

単に「ScreenLoggerのコンストラクターに電話をかけ、スクリーンハンドラーで初期化する」と言っています。私がscrhを保護されたものと定義したことはここでは注目に値する。したがって、 DeepLoggerからこのプロパティにも同様にアクセスできます。プロパティがプライベートとして定義されている場合それを初期化する唯一の方法は、コンスータを使用することです。

別の変更はセクションmethodsます。繰り返しを避けるため、親クラスのLogMessage()を呼び出してメッセージを画面に記録します。画面のロギングを改善するために何かを変更しなければならなかったら、今は1か所でやる必要があります。残りのコードはDeepLogger一部とDeepLoggerです。

このクラスも抽象クラスMessageLoggerから継承するので、 DeepLogger内のLogMessage()も定義されていることを確認しなければなりませんDeepLoggerMessageLoggerから継承するのはちょっと難しいです。私は、 LogMessage再定義が必須であると思う - 私の推測。

ロガーが適用されるコードに関しては、クラス内の共通インターフェースのおかげで、コード全体でこの1行を変更することは問題にならないでしょう。同じメッセージが以前と同じようにログオンされますが、さらにコードはそのようなメッセージをファイルに書き込みます。

clc;
% ... a code
logger = DeepLogger(1, 'mylogfile.log');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');
% ... a code
logger.LogMessage('something');

私は、これらの例がクラスの使用、継承の使用、抽象クラスの使用について説明してくれることを願っています。


PS。上記の問題に対する解決法は、多くのうちの1つです。あまり複雑ではない別の解決策は、 ScreenLogerFileLoggerなどのような別のロガーのコンポーネントにすることですScreenLoggerはプロパティの1つに保持されます。 LogMessageは単にScreenLogger LogMessageを呼び出し、スクリーン上にテキストを表示します。 MATLABでクラスがどのように動作するかをむしろ示すために、より複雑なアプローチを選択しました。以下のサンプルコード:

classdef DeepLogger < MessageLogger
    properties(SetAccess=protected)
        FileName
        Path
        ScrLogger
    end
    methods
        function obj = DeepLogger(screenhandler, filename)
            [path,filen,ext] = fileparts(filename);
            obj.FileName     = [filen ext];
            obj.Path         = pathn;
            obj.ScrLogger    = ScreenLogger(screenhandler);
        end
        function LogMessage(obj, varargin)
            if ~isempty(varargin)
                varargin{1} = num2str(varargin{1});
                obj.LogMessage(obj.ScrLogger, varargin{:}); % <-------- thechange here
                fid = fopen(obj.fullfname, 'a+t');
                fprintf(fid, '%s\n', sprintf(varargin{:}));
                fclose(fid);
            end
        end
    end
end

コンストラクタ

コンストラクタは、オブジェクトのインスタンスが作成されるときに呼び出されるクラス内の特別なメソッドです。これは入力パラメータを受け入れる通常のMATLAB関数ですが、特定の規則にも従わなければなりません。

MATLABがデフォルトのものを作成するので、コンストラクタは必須ではありません。しかし、実際には、これはオブジェクトの状態を定義する場所です。たとえば、 属性を指定することでプロパティを制限することができます 。次に、コンストラクタは、実際にはコンストラクタの入力パラメータによって送信できるデフォルトまたはユーザ定義の値によって、そのようなプロパティを初期化できます。

単純なクラスのコンストラクタを呼び出す

これは単純なクラスPersonです。

classdef Person
    properties
        name
        surname
        address
    end
    
    methods
        function obj = Person(name,surname,address)
            obj.name = name;
            obj.surname = surname;
            obj.address = address;
        end
    end
end

コンストラクタの名前は、クラスの名前と同じです。したがって、コンストラクタはそのクラスの名前で呼び出されます。 Personクラスは、次のように作成できます。

>> p = Person('John','Smith','London')
p = 
  Person with properties:

       name: 'John'
    surname: 'Smith'
    address: 'London'

子クラスのコンストラクタを呼び出す

共通のプロパティまたはメソッドを共有する場合、クラスは親クラスから継承できます。クラスが別のクラスから継承される場合、親クラスのコンストラクタを呼び出さなければならない可能性があります。

クラスMemberクラスから継承するPersonので、 MemberクラスPersonと同じプロパティを使用していますが、それはまた、追加paymentその定義に。

classdef Member < Person
    properties
        payment
    end

    methods
        function obj = Member(name,surname,address,payment)
            obj = obj@Person(name,surname,address);
            obj.payment = payment;
        end
    end
end

Personクラスと同様に、 Memberはそのコンストラクタを呼び出して作成されます:

>> m = Member('Adam','Woodcock','Manchester',20)
m = 
  Member with properties:

    payment: 20
       name: 'Adam'
    surname: 'Woodcock'
    address: 'Manchester'

Personのコンストラクタには3つの入力パラメータが必要です。 Memberはこの事実を尊重しなければならないため、3つのパラメータを持つPersonクラスのコンストラクタを呼び出します。それは次の行によって実現されます:

obj = obj@Person(name,surname,address);

上記の例は、子クラスが親クラスの情報を必要とする場合を示しています。これは、 Memberコンストラクターが4つのパラメーターを必要とする理由です.3つはその親クラス用であり、もう1つはそれ自身のパラメーターです。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow