Skip to content

MATLAB - 函数重载

在 MATLAB 中,处理同名函数主要有两种方式:通过改变输入参数数量来实现函数重载(function overloading),以及在面向对象编程中实现方法重写(method overriding)。这使您能够创建灵活直观的接口,其中单个函数名可以根据其被调用的上下文调整其行为。

这些技术是编写整洁、可复用且专业的 MATLAB 代码的基础。它们使您能够:

  • 创建灵活的函数:设计一个能够根据输入数量或类型执行不同操作的单一函数,从而减少创建许多类似命名函数(例如,addTwoNumbers、addThreeNumbers)的必要。
  • 为自定义类定制行为:使您的自定义类对象表现得像 MATLAB 的内置类型一样。例如,您可以定义 plot 或 disp 函数应如何专门为您的对象工作。
  • 扩展现有功能:在面向对象编程中,子类可以提供其从父类继承的方法的专门版本(重写),从而在不改变父类的情况下定制其行为。

MATLAB 的方法取决于您是在编写过程式脚本还是在定义类。

1. 使用可变参数 (nargin) 进行重载

Section titled “1. 使用可变参数 (nargin) 进行重载”

对于标准函数(不在类中),您可以通过使用 nargin 关键字检查用户提供的输入参数数量来模拟重载。这允许单个函数展现不同的行为。

2. 面向对象编程 (OOP) 中的方法重写

Section titled “2. 面向对象编程 (OOP) 中的方法重写”

在 OOP 中,当您创建一个类时,您可以定义与现有 MATLAB 函数(例如 plot、disp)或超类中的方法同名的方法。当您使用您的类对象调用该函数时,MATLAB 的调度机制会调用您类特有的方法。这被称为重写(overriding)。

  • 主导参数规则(Dominant Argument Rule):当函数使用不同类的参数调用时,MATLAB 根据类层次结构确定要调用的方法。用户定义的类优先于内置类型。
  • 实现:要重写一个函数,只需在您的 classdef 文件中定义一个同名方法。此方法必须接受您的类对象作为参数。

与其创建多个 add 方法,不如使用 nargin 或 varargin 在单个方法中处理可变数量的输入,这是一种更现代、更健壮的方法。下面是一个计算矩形或正方形面积的函数。

function area = calculateArea(width, height)
% Calculates the area of a shape.
% If one input is provided, it's treated as a square.
% If two inputs are provided, it's treated as a rectangle.
% 计算形状的面积。
% 如果提供一个输入,则将其视为正方形。
% 如果提供两个输入,则将其视为矩形。
narginchk(1, 2); % Ensure 1 or 2 inputs are given
% 确保给定 1 或 2 个输入
if nargin == 1
% Square: area = side^2
% 正方形:面积 = 边长^2
area = width^2;
fprintf('Calculating area of a square with side %.2f\n', width);
else
% Rectangle: area = width * height
% 矩形:面积 = 宽 * 高
area = width * height;
fprintf('Calculating area of a rectangle with width %.2f and height %.2f\n', width, height);
end
end
% --- How to use it ---
% --- 如何使用 ---
area1 = calculateArea(5); % Called with one argument
% 使用一个参数调用
disp(['Area 1: ', num2str(area1)]);
area2 = calculateArea(5, 10); % Called with two arguments
% 使用两个参数调用
disp(['Area 2: ', num2str(area2)]);

当您运行此代码时,MATLAB 的 nargin 检查会将流程导向正确的计算,从而有效地重载了 calculateArea 函数的行为。

示例 2:为自定义类重写 disp 函数

Section titled “示例 2:为自定义类重写 disp 函数”

让我们创建一个 Patient 类并重写内置的 disp 函数,以便在 Patient 对象打印到控制台时提供自定义的、信息更丰富的显示。

classdef Patient
properties
Name string
ID double
Data double
end
methods
function obj = Patient(name, id, data)
if nargin > 0
obj.Name = name;
obj.ID = id;
obj.Data = data;
end
end
% Override the built-in disp() function
% 重写内置的 disp() 函数
function disp(obj)
fprintf('--- Patient Record ---\n');
fprintf(' Name: %s\n', obj.Name);
fprintf(' ID: %d\n', obj.ID);
fprintf(' Data Points: %d\n', numel(obj.Data));
fprintf(' Mean Value: %.2f\n', mean(obj.Data));
fprintf('----------------------\n');
end
end
end
% --- How to use it ---
% --- 如何使用 ---
% Create an instance of the Patient class
% 创建 Patient 类的实例
p = Patient("John Doe", 123, [98.6, 99.1, 98.4, 98.7]);
% Now, just typing the variable name in the command window will call our custom disp method
% 现在,只需在命令窗口中输入变量名就会调用我们自定义的 disp 方法
disp(p);

如果没有重写 disp 方法,MATLAB 将显示一个通用的对象属性列表。有了它,我们就能得到一个为我们的类量身定制的整洁、格式化的摘要。

方法重写是继承的核心。子类可以提供其超类中方法的自己的版本。在这里,Circle 和 Rectangle 都继承自 Shape,但它们都提供了自己特定的 calculateArea 方法。

% --- Base Class: Shape.m ---
% --- 基类:Shape.m ---
classdef Shape
methods
function a = calculateArea(obj)
disp('Area calculation not defined for a generic shape.');
% 泛型形状未定义面积计算。
a = NaN; % Not a Number
% 非数字
end
end
end
% --- Subclass: Circle.m ---
% --- 子类:Circle.m ---
classdef Circle < Shape
properties
Radius
end
methods
function obj = Circle(r)
obj.Radius = r;
end
% Override calculateArea for Circle
% 为 Circle 重写 calculateArea
function a = calculateArea(obj)
a = pi * obj.Radius^2;
end
end
end
% --- Subclass: Rectangle.m ---
% --- 子类:Rectangle.m ---
classdef Rectangle < Shape
properties
Width
Height
end
methods
function obj = Rectangle(w, h)
obj.Width = w;
obj.Height = h;
end
% Override calculateArea for Rectangle
% 为 Rectangle 重写 calculateArea
function a = calculateArea(obj)
a = obj.Width * obj.Height;
end
end
end
% --- How to use it ---
% --- 如何使用 ---
shape = Shape();
circle = Circle(10);
rectangle = Rectangle(5, 8);
area1 = shape.calculateArea(); % Calls Shape's method
% 调用 Shape 的方法
area2 = circle.calculateArea(); % Calls Circle's method
% 调用 Circle 的方法
area3 = rectangle.calculateArea(); % Calls Rectangle's method
% 调用 Rectangle 的方法
fprintf('Generic Shape Area: %.2f\n', area1);
disp(['Circle Area: ', num2str(area2)]);
disp(['Rectangle Area: ', num2str(area3)]);