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);调用函数。
1. 基础规则
classdel定义类名,<表示继承,Matlab允许多重继承,继承自handle类,handle类定义了很多关于object的处理函数。
类的方法是放在methods ...end里面。
下面一则实例:
classdef TensileData % 定义类的名称
properties %% 定义类的属性,相当于C++中的成员函数
Material = 'carbon steel';
SampleNumber = 0;
Stress
Strain
end
properties (Dependent) %% 定义依赖型属性,该属性只能通过类内的方法进行赋值,参考modulus = get.Modulus(obj)
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') % 只能通过类的成员进行访问 私有成员方法
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
2. 关于封装造成的时间开销
面向对象的使用必然导致程序的开销变高,封装后的函数多次调用会话费相当长的时间。
所以到底该不该封装,还需取决于实际情况,如果函数本身特别简单,并且会被循环调用,最好还是通过m文件函数的形式。之前MIT大牛给出了更多地建议
1.虽然for-loop的速度有了很大改善,vectorization(向量化)仍旧是改善效率的重要途径,尤其是在能把运算改写成矩阵乘法的情况下,改善尤为显著。
2.在不少情况下,for-loop本身已经不构成太大问题,尤其是当循环体本身需要较多的计算的时候。这个时候,改善的关键在于改善循环体本身而不是去掉for-loop。
3.MATLAB的函数调用过程(非built-in function)有显著开销,因此,在效率要求较高的代码中,应该尽可能采用扁平的调用结构,也就是在保持代码清晰和可维护的情况下,尽量直接写表达式和利用built-in function,避免不必要的自定义函数调用过程。在次数很多的循环体内(包括在cellfun, arrayfun等实际上蕴含循环的函数)形成长调用链,会带来很大的开销。
4.在调用函数时,首选built-in function,然后是普通的m-file函数,然后才是function handle或者anonymous function。在使用function handle或者anonymous function作为参数传递时,如果该函数被调用多次,最好先用一个变量接住,再传入该变量。这样,可以有效避免重复的解析过程。
5.在可能的情况下,使用numeric array或者struct array,它们的效率大幅度高于cell array(几十倍甚至更多)。对于struct,尽可能使用普通的域(字段,field)访问方式,在非效率关键,执行次数较少,而灵活性要求较高的代码中,可以考虑使用动态名称的域访问。
6.虽然object-oriented从软件工程的角度更为优胜,而且object的使用很多时候很方便,但是MATLAB目前对于OO的实现效率很低,在效率关键的代码中应该慎用objects。
7.如果需要设计类,应该尽可能采用普通的property,而避免灵活但是效率很低的dependent property。如非确实必要,避免重载subsref和subsasgn函数,因为这会全面接管对于object的接口调用,往往会带来非常巨大的开销(成千上万倍的减慢),甚至使得本来几乎不是问题的代码成为性能瓶颈。
文章引用:https://blog.csdn.net/beechina/article/details/50933860