关于matlab.mixin.Copyable子类重载copyElement方法的技术问询
matlab.mixin.Copyable 核心特性与技术疑问解答
官方核心特性梳理
matlab.mixin.Copyable的官方文档明确以下关键特性:
- copy方法默认执行浅拷贝
copyElement是受保护方法,copy方法通过它对数组中的每个对象完成拷贝操作- MATLAB不会对属性中的句柄类型递归调用copy
- copy方法拷贝时不触发类构造函数或属性设置函数,无副作用
疑问1:copy方法到底是浅拷贝还是深拷贝?
文档说明copy默认是浅拷贝,但测试代码中对DeepCp对象使用copy得到了类似深拷贝的效果,原因如下:
matlab.mixin.Copyable的默认copyElement实现是浅拷贝:对于值类型属性,复制的是值本身;对于句柄类型属性,仅复制句柄引用(新旧对象共享同一个句柄实例)。- 你的测试类
DeepCp的属性DpProp是数值类型(值类型),值类型的拷贝天然是“值复制”,修改原对象属性不会影响拷贝对象,因此看起来是深拷贝。如果属性是句柄类型,默认copy的浅拷贝特性会立刻体现:classdef HandleProp < handle properties Val end end classdef TestCopy < matlab.mixin.Copyable properties HProp HandleProp end end % 测试浅拷贝行为 t = TestCopy; t.HProp = HandleProp; t.HProp.Val = 10; t_copy = copy(t); t.HProp.Val = 20; disp(t_copy.HProp.Val); % 输出20,说明新旧对象共享句柄 - 官方示例中调用
copy(obj.DeepObj),是因为DeepObj是另一个继承自matlab.mixin.Copyable的对象——此时copy调用的是DeepObj类的拷贝逻辑,若DeepObj的类重载了copyElement,就能实现自定义深拷贝。本质上copy是框架入口方法,真正的拷贝逻辑由copyElement决定,默认是浅拷贝,但可通过重载copyElement实现深拷贝。
疑问2:重载copyElement是否必须声明Access=protected?
- 是的,必须声明
Access = protected。父类matlab.mixin.Copyable的copyElement是受保护方法,MATLAB要求子类重载方法的访问权限不能比父类更宽松(比如不能改为public),否则会触发语法错误。 - 在MATLAB中重载父类/内置方法时,必须保持方法的核心属性一致,包括访问权限、密封状态(若父类方法为sealed则无法重载)、静态/抽象标识等。如果父类方法带有其他属性,子类重载时必须完全匹配。
疑问3:为什么调用父类copyElement是浅拷贝,直接用copy却能得到深拷贝?
- 直接调用
copy(obj)最终一定会调用copyElement:copy是对外的公共接口,它会遍历对象数组,对每个元素调用copyElement完成拷贝。 - 父类默认的
copyElement是浅拷贝,你测试的DeepCp对象因为属性是值类型,所以copy调用默认copyElement后,呈现出深拷贝的效果(值类型的拷贝特性导致)。若DeepCp的属性是句柄类型,默认copy就会体现浅拷贝的本质。 - 官方示例中先调用
copyElement@matlab.mixin.Copyable(obj)得到浅拷贝对象,再手动对DeepObj调用copy,是为了对这个特定的句柄/复杂对象实现深拷贝——默认浅拷贝只会复制DeepObj的引用,手动调用copy可以让DeepObj自身完成拷贝(若其类重载了copyElement)。
疑问4:copy是密封方法,为什么文档说不会递归调用copy?
- 这里的“递归调用”指:当对象的属性是另一个
matlab.mixin.Copyable类型的对象时,默认copy不会自动对该属性对象调用copy。比如对象A有属性B(matlab.mixin.Copyable类型),默认copy(A)只会复制B的引用,不会自动执行copy(B)——这就是文档所说的“不会递归调用copy”。 - copy方法是密封的意味着无法重载copy本身,但可通过重载
copyElement控制拷贝逻辑,比如在copyElement里手动对嵌套属性调用copy,实现类似“递归拷贝”的效果(即官方示例的做法)。文档这句话是说明默认行为,而非提示递归风险,目的是告知开发者:若需要深拷贝嵌套对象,必须在copyElement中手动处理。
疑问5:哪些内置方法会调用构造/属性设置函数?有什么副作用?
- 会触发构造函数或属性设置函数的内置方法包括:
- 直接实例化类:
obj = ClassName(args)(调用构造函数) - 直接赋值属性:
obj.Property = value(调用属性setter) - handle类的
clone方法(默认调用构造函数) - 序列化/反序列化方法(如
save/load,若类自定义了序列化逻辑)
- 直接实例化类:
- 可能产生的副作用:
- 构造函数中的初始化逻辑(如打开文件、建立连接)被重复执行,导致资源泄漏或重复初始化
- 属性设置函数中的验证、联动逻辑(如修改其他属性、触发事件)被意外触发,导致对象状态异常
- 性能开销:构造函数和设置函数的执行效率远低于copy方法的直接内存拷贝
内容的提问来源于stack exchange,提问作者bokabokaboka
相关产品推荐
相关产品推荐

