Skip to content

MATLAB - Operator Overloading

Operator overloading allows you to define the behavior of standard MATLAB operators like +, -, *, and == for objects of your own custom class. This powerful feature lets you create intuitive and readable code, enabling your custom objects to interact as naturally as built-in types like numbers and matrices.

Imagine you have a class that represents a complex number or a polynomial. Without operator overloading, adding two such objects would require a verbose method call like p3 = p1.add(p2). By overloading the + operator, you can simply write p3 = p1 + p2;, which is more concise and mathematically intuitive.

  • Intuitive Syntax: Perform arithmetic (v1 + v2), relational (obj1 == obj2), and logical operations directly on your objects.
  • Seamless Integration: Allows your custom objects to be used with standard MATLAB functions and syntax that expect these operators to work.
  • Code Readability: Makes your code cleaner and easier to understand by mirroring standard mathematical and logical notation.

To overload an operator, you implement a specific method within your classdef file. MATLAB maps each operator to a corresponding method name. When an operator is used with an object of your class, MATLAB calls the associated method.

Here are some common operators and their corresponding method names:

OperatorMethod NameDescription
+plusBinary addition (e.g., a + b)
-minusBinary subtraction (e.g., a - b)
*mtimesMatrix multiplication (e.g., a * b)
.*timesElement-wise multiplication (e.g., a .* b)
==eqEquality comparison (e.g., a == b)
<ltLess than comparison (e.g., a < b)
-auminusUnary minus (e.g., -a)

MATLAB evaluates expressions according to a fixed order of operator precedence. For example, multiplication (*) is performed before addition (+). You can use parentheses () to explicitly control the order of evaluation and improve code clarity. It’s a best practice to use parentheses whenever an expression’s evaluation order might seem ambiguous.

% Default precedence: exponentiation (^) before division (/)
A = [3 9 5];
B = [2 1 5];
C1 = A ./ B.^2
% C1 = [0.7500 9.0000 0.2000]
% Using parentheses to override precedence: division before exponentiation
C2 = (A ./ B).^2
% C2 = [2.2500 81.0000 1.0000]

Let’s create a Vector2D class representing a 2D vector and overload several operators to make vector arithmetic simple and natural.

classdef Vector2D
properties
X {mustBeNumeric, mustBeFinite} = 0
Y {mustBeNumeric, mustBeFinite} = 0
end
methods
function obj = Vector2D(x, y)
% Constructor
if nargin == 2
obj.X = x;
obj.Y = y;
end
end
% Overload the plus operator (+)
function result = plus(v1, v2)
% Ensure both operands are Vector2D objects
if ~isa(v1, 'Vector2D') || ~isa(v2, 'Vector2D')
error('Both operands must be Vector2D objects for addition.');
end
result = Vector2D(v1.X + v2.X, v1.Y + v2.Y);
end
% Overload the minus operator (-)
function result = minus(v1, v2)
result = Vector2D(v1.X - v2.X, v1.Y - v2.Y);
end
% Overload the mtimes operator (*) for scalar multiplication
function result = mtimes(v, scalar)
if isa(v, 'Vector2D') && isscalar(scalar)
result = Vector2D(v.X * scalar, v.Y * scalar);
elseif isscalar(v) && isa(scalar, 'Vector2D')
% Handle the case `scalar * vector`
result = Vector2D(scalar.X * v, scalar.Y * v);
else
error('Unsupported multiplication. Use a Vector2D and a scalar.');
end
end
% Overload the equality operator (==)
function areEqual = eq(v1, v2)
areEqual = (v1.X == v2.X) && (v1.Y == v2.Y);
end
% Custom display method for clarity
function disp(obj)
fprintf(' Vector2D | X: %.2f, Y: %.2f\n', obj.X, obj.Y);
end
end
end

Save the code above as Vector2D.m. Now, you can use these intuitive operations in a script:

% Create two Vector2D objects
v1 = Vector2D(3, 4);
v2 = Vector2D(1, 2);
disp('Vector v1:'); disp(v1);
disp('Vector v2:'); disp(v2);
% --- Test the overloaded operators ---
% Test addition (+)
v_sum = v1 + v2;
disp('v1 + v2 ='); disp(v_sum);
% Test subtraction (-)
v_diff = v1 - v2;
disp('v1 - v2 ='); disp(v_diff);
% Test scalar multiplication (*)
v_scaled = v1 * 3;
disp('v1 * 3 ='); disp(v_scaled);
% Test equality (==)
is_equal = (v1 == Vector2D(3, 4));
disp(['Are v1 and Vector2D(3, 4) equal? ', mat2str(is_equal)]);
is_notequal = (v1 == v2);
disp(['Are v1 and v2 equal? ', mat2str(is_notequal)]);

When overloading operators, it’s crucial to ensure they behave as expected. A good practice is to create a separate test script to verify the logic.

  • Handle Different Operand Types: Your method should gracefully handle cases where operands might be of different types (e.g., your object and a scalar double), as shown in the mtimes example.
  • Validate Inputs: Use functions like isa to check object types and isscalar, isnumeric, etc., to validate inputs and provide meaningful errors.
  • Write Tests: Create a script that asserts expected outcomes. For example, assert(isequal(v1 + v2, Vector2D(4, 6))) can automatically verify your addition logic. This becomes invaluable as your class grows in complexity.