Matlab也可以寫面向對象的代碼,首先表現在可以定義類,以及可以繼承,使用類(class)有很多好處,其中一個重要的好處便是解決變量名衝突和讓函數、對象的結構清晰。class的static function可以在不定義類的實例直接調用類的成員函數,比如定義
classdef tools < handle
methods (Static = true)
function a = test(b, c)
a = b + c;
end
end
end
然後可以直接通過
a = tools.test(b, c);調用函數。
classdel是定義類名,後面的<是表示繼承,Matlab允許多重繼承,繼承自handle類,handle類定義了很多關於object的處理函數,例如addListener以及notify還有delete等對對象的函數,是一個抽象類,不能實例化,具體可以看一下參考文獻【2】。
類的方法是放在methods ...end裏面。
下面是一個稍微複雜的類的定義
classdef TensileData
properties
Material = 'carbon steel';
SampleNumber = 0;
Stress
Strain
end
properties (Dependent)
Modulus
end
methods
function td = TensileData(material,samplenum,stress,strain)
if nargin > 0
td.Material = material;
td.SampleNumber = samplenum;
td.Stress = stress;
td.Strain = strain;
end
end % TensileData
end
methods
function obj = set.Material(obj,material)
if ~(strcmpi(material,'aluminum') ||...
strcmpi(material,'stainless steel') ||...
strcmpi(material,'carbon steel'))
error('Material must be aluminum, stainless steel, or carbon steel')
end
obj.Material = material;
end % Material set function
function modulus = get.Modulus(obj)
ind = find(obj.Strain > 0); % Find nonzero strain
modulus = mean(obj.Stress(ind)./obj.Strain(ind));
end % Modulus get function
function obj = set.Modulus(obj,~)
fprintf('%s%d\n','Modulus is: ',obj.Modulus)
error('You cannot set Modulus explicitly');
end
function disp(td)
fprintf(1,'Material: %s\nSample Number: %g\nModulus: %1.5g\n',...
td.Material,td.SampleNumber,td.Modulus);
end % disp
function plot(td,varargin)
plot(td.Strain,td.Stress,varargin{:})
title(['Stress/Strain plot for Sample ',num2str(td.SampleNumber)])
xlabel('Strain %')
ylabel('Stress (psi)')
end % plot
end
methods (Access = 'private') % Access by class members only
function m = CalcModulus(td)
% Over-simplified calculation of Elastic Modulus
ind = find(td.Strain > 0); % Find nonzero strain
m = mean(td.Stress(ind)./td.Strain(ind));
end % CalcModulus
end
end % classdef
在上述代碼中,
classdef TensileData
...
end
是定義一個TensileData類。代碼:
properties
Material = 'carbon steel';
SampleNumber = 0;
Stress
Strain
end
是定義這個類的屬性,也就是C++中類的成員變量。但是和C++不同的是,matlab中的類定義還有一個比較特別的地方的,就是定義依賴屬性,如下述代碼:
properties (Dependent)
Modulus
end
這表示Modulus這個屬性是個依賴屬性,它的值是通過其他屬性計算得到的,其中Dependent的默認屬性值爲True。
它的值是通過下面函數實現的:
% Modulus get function
function modulus = get.Modulus(obj)
ind = find(obj.Strain > 0); % Find nonzero strain
modulus = mean(obj.Stress(ind)./obj.Strain(ind));
end
類的方法(函數)的定義是以methods ... end的的形式出現的。如下面的類方法的定義:
methods
function td = TensileData(material,samplenum,stress,strain)
if nargin > 0
td.Material = material;
td.SampleNumber = samplenum;
td.Stress = stress;
td.Strain = strain;
end
end
end
該函數塊定義了TensileData構造函數方法。上述代碼中的最後一個方法 methods (Access = 'private')
中的Access = 'private'表示該方法僅能被類本身訪問和修改,是個私有成員方法。其中屬性Access又可分爲
SetAccess和GetAccess,屬性值和Access相同。
面向對象的使用必然導致程序的開銷變高,關於相關的討論可以看一下【1】:封裝後的函數多次調用會話費相當長的時間
所以到底該不該封裝,還需取決於實際情況,如果函數本身特別簡單,並且會被循環調用,最好還是通過m文件函數的形式。之前MIT大牛給出了更多地建議
- 雖然for-loop的速度有了很大改善,vectorization(向量化)仍舊是改善效率的重要途徑,尤其是在能把運算改寫成矩陣乘法的情況下,改善尤爲顯著。
- 在不少情況下,for-loop本身已經不構成太大問題,尤其是當循環體本身需要較多的計算的時候。這個時候,改善概率的關鍵在於改善循環體本身而不是去掉for-loop。
- MATLAB的函數調用過程(非built-in function)有顯著開銷,因此,在效率要求較高的代碼中,應該儘可能採用扁平的調用結構,也就是在保持代碼清晰和可維護的情況下,儘量直接寫表達式和利用built-in function,避免不必要的自定義函數調用過程。在次數很多的循環體內(包括在cellfun, arrayfun等實際上蘊含循環的函數)形成長調用鏈,會帶來很大的開銷。
- 在調用函數時,首選built-in function,然後是普通的m-file函數,然後纔是function handle或者anonymous function。在使用function handle或者anonymous function作爲參數傳遞時,如果該函數被調用多次,最好先用一個變量接住,再傳入該變量。這樣,可以有效避免重複的解析過程。
- 在可能的情況下,使用numeric array或者struct array,它們的效率大幅度高於cell array(幾十倍甚至更多)。對於struct,儘可能使用普通的域(字段,field)訪問方式,在非效率關鍵,執行次數較少,而靈活性要求較高的代碼中,可以考慮使用動態名稱的域訪問。
- 雖然object-oriented從軟件工程的角度更爲優勝,而且object的使用很多時候很方便,但是MATLAB目前對於OO的實現效率很低,在效率關鍵的代碼中應該慎用objects。
- 如果需要設計類,應該儘可能採用普通的property,而避免靈活但是效率很低的dependent property。如非確實必要,避免重載subsref和subsasgn函數,因爲這會全面接管對於object的接口調用,往往會帶來非常巨大的開銷(成千上萬倍的減慢),甚至使得本來幾乎不是問題的代碼成爲性能瓶頸。
參考文獻:
【1】http://zhiqiang.org/blog/it/class-wrapper-functions-in-matlab.html
【2】http://cn.mathworks.com/help/matlab/ref/handle.html?searchHighlight=handle
【3】http://www.cnblogs.com/magic-cube/archive/2011/11/08/2241580.html
【4】http://anony3721.blog.163.com/blog/static/5119742011911111232557/