Skip to content

MATLAB - 复制对象

在 MATLAB 中,对象的复制方式取决于其类。有两种基本行为:值(value)和句柄(handle)。理解这种区别对于编写可预测且无错误的对象导向代码至关重要,尤其是在对象状态被共享和修改的大型应用程序中。

默认情况下,MATLAB 中的类具有值语义(value semantics)。当您复制一个值对象时,您会创建一个全新的、完全独立的该对象实例。这就像复印一份文件:对副本的更改不会影响原件。

所有内置的 MATLAB 数据类型,如 double、char 和 struct 都是值类型。

classdef ValueClass
properties
Data = 0;
end
end
%% 创建值类的实例
obj1 = ValueClass;
obj1.Data = 10;
%% 复制对象 - MATLAB 会创建一个独立的深拷贝
obj2 = obj1;
%% 修改副本
obj2.Data = 20;
%% 检查两个对象的数据
fprintf('obj1.Data = %d\n', obj1.Data); % 输出: obj1.Data = 10
fprintf('obj2.Data = %d\n', obj2.Data); % 输出: obj2.Data = 20
% 如你所见,修改 obj2 并未影响 obj1。

要创建句柄类,您必须继承内置的 handle 类。当您复制句柄对象变量时,您不是在创建一个新对象。相反,您是创建了一个指向同一个底层对象的新引用(或句柄)。这就像共享一个 Google 文档的链接:任何拥有该链接的人都可以编辑同一份文档。

classdef HandleClass < handle
properties
Data = 0;
end
end
%% 创建句柄类的实例
obj1 = HandleClass;
obj1.Data = 10;
%% “复制”对象 - 这只是复制了句柄(引用)
obj2 = obj1;
%% 通过第二个句柄修改对象
obj2.Data = 20;
%% 检查两个对象的数据
fprintf('obj1.Data = %d\n', obj1.Data); % 输出: obj1.Data = 20
fprintf('obj2.Data = %d\n', obj2.Data); % 输出: obj2.Data = 20
% 通过 obj2 修改数据影响了底层唯一的对象,
% 因此 obj1 也能看到此更改。

最佳实践:创建句柄对象的真副本

Section titled “最佳实践:创建句柄对象的真副本”

如果您有一个句柄对象,但需要一个独立的副本怎么办?最佳实践是在您的句柄类中实现一个自定义的 copy 方法。该方法将创建一个该类的新实例并复制属性值。

此模式通常涉及一个受保护的 copyElement 方法,这是 MathWorks 建议的用于创建深拷贝的约定。

classdef CopyableHandle < handle
properties
Name
Data
end
methods
function obj = CopyableHandle(name, data)
if nargin > 0
obj.Name = name;
obj.Data = data;
end
end
% 公共复制方法
function new_obj = copy(self)
% 创建一个同类的新对象
new_obj = feval(class(self));
% 调用受保护的方法来复制属性
self.copyElement(new_obj);
end
end
methods (Access = protected)
% 处理实际属性复制的受保护方法
function copyElement(self, new_obj)
props = properties(self);
for i = 1:length(props)
new_obj.(props{i}) = self.(props{i});
end
end
end
end
%% 创建原始对象
original = CopyableHandle('Sensor A', [1, 2, 3]);
%% 使用自定义复制方法创建深拷贝
deepCopy = original.copy();
%% 修改副本
deepCopy.Name = 'Sensor B Clone';
deepCopy.Data(1) = 99;
%% 显示结果以证明它们是独立的
disp('原始对象:');
disp(original);
disp('复制对象:');
disp(deepCopy);
% 请注意,只有复制对象的属性发生了变化。

copyobj 函数主要用于复制图形对象(它们是句柄对象)从一个父级到另一个父级,例如将 axes 从一个 figure 复制到另一个 figure。它是 MATLAB 较旧的图形系统的一部分,但在特定情况下仍然有用。

copyobj 的主要特点:

  • 新对象获得一个新的句柄。
  • 新对象的 Parent 属性会更新。
  • 它通常不复制回调或应用程序数据,以避免意外行为。
% 创建一个带有一些图形对象的图窗
fig1 = figure('Name', 'Original Figure');
ax1 = axes('Parent', fig1);
plot(ax1, 1:10, rand(1, 10), 'LineWidth', 2);
title(ax1, 'Original Plot');
% 创建第二个图窗作为新的父级
fig2 = figure('Name', 'Copied Figure');
% 将轴对象从 fig1 复制到 fig2
newAx = copyobj(ax1, fig2);
% 修改副本以证明它是独立的
title(newAx, 'Copied Plot');
newAx.Color = [0.9 0.9 0.95]; % 更改背景颜色
% 原始图窗保持不变。