在之前的文章中,我们都默认使用的类是handle类,因为在定义类的时候都有一句:

classdef Point < handle

我们在类的继承中知道,这句代码的意思是 Point是handle类的一个子类,其实我们也可以不加后面的,直接写成:

classdef Point

这样声明的类就是一个 Value类,那么二者有什么区别,又怎样使用呢?


我们先定义两个类,分别为 PointValue 和PointHandle
PointValue类

% PointValue.m
classdef PointValue  % 未继承handle 基类
    properties
        x
        y
    end
    methods
        function obj = PointValue(x,y)
    obj.x = x;
    obj.y = y;
        end
        function changeX(obj,x)
            obj.x = x;
        end
    end
end
% 二者的区别在于Value每次传入copy,但是handle传入的是地址,可以直接修改
% 即 handle类函数的输入参数为 &a Value类函数传入的是copy,作用域外销毁

PointHandle类

% PointHandle.m
classdef PointHandle < handle  % 继承handle 基类
    properties
        x
        y
    end
    methods
        function obj = PointHandle(x,y)
    obj.x = x;
    obj.y = y;
        end
        function changeX(obj,x)
            obj.x = x;
        end
    end
end

Handle 类我们可以看成句柄,Value类就是实值。我们在C++中,有时候需要输入参数为 &x,而handle类和Value类有点类似于 &x和x的区别,我们以一个 changeX()方法来说明。可以看到上面两个类的定义只有第一行不同,changeX()是希望通过这个函数改变x的值,我们运行下面代码:

a = PointValue(1,1)
b = PointHandle(1,1)
a.changeX(5)
b.changeX(5)
a
b
% Value类没能修改x的值,Handle能够改
% 如果Value更改需要将值传出来改
% Value类需要这样更改 function obj = changeX(obj,x)


从结果可以看出,changeX并没有改变x的值,因为此时传入的是obj的一个副本,离开作用域之后又自动销毁了,不会影响到原来的obj,但是Handle类传入的是地址,在类方法内部修改会对原参数产生影响。如果Value类希望达到同样的效果,需要写成obj = changeX(obj,x),来将修改后的值输出。


我们再举一个例子来说明。
还是上面的定义,运行下面的代码:

a = PointHandle(5,5);
a1 = a;
a1.delete();
a

这里的意思是,删掉a1,我们看看结果:

这说明 a和a1指向的同一个内存,删掉了a1指向的地方 a就无效了,但是Value类没有析构函数,不能用delete,像PointValue1 = PointValue这样的代码,其实会拷贝出两个独立的内存,互不干扰。