From 0b9af04f70496fb3dd7e912eb8cb6ddbe72be227 Mon Sep 17 00:00:00 2001 From: fenglielie Date: Sun, 1 Jun 2025 23:23:57 +0800 Subject: [PATCH] doc: update docs/matlab.md (#969) --- docs/matlab.md | 396 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) diff --git a/docs/matlab.md b/docs/matlab.md index ac15c797..4d956425 100644 --- a/docs/matlab.md +++ b/docs/matlab.md @@ -1410,6 +1410,402 @@ true 或 false 条件 [thingSpeakWrite](https://ww2.mathworks.cn/help/matlab/ref/thingspeakwrite.html) | 将数据写入 `ThingSpeak` 通道 +## 面向对象基础 + +MATLAB 支持面向对象编程,虽然很少有人使用。 + +MATLAB 的自定义类型可以分成全值类和句柄类,它们的区别在于句柄类相当于指针,赋值时只会进行浅拷贝,全值类总是会进行深拷贝。下面的例子只涉及全值类。 + +### 简单例子 + +一个简单的 `point2d` 类(文件名必须与类名相同:`point2d.m` ) + +```matlab +classdef point2d + properties % 属性 + x + y + end + methods % 方法 + function obj = point2d(x0,y0) % 构造方法 + if nargin == 0 + obj.x = 0; + obj.y = 0; + elseif nargin == 2 + obj.x = x0; + obj.y = y0; + else + error("unsupported arguments") + end + end + function obj = normalize(obj) % 普通方法 + % obj 相当于 Python 的 self + r = sqrt(obj.x^2+obj.y^2); + obj.x = obj.x/r; + obj.y = obj.y/r; + end + end +end +``` + +使用例如 + +```matlab +a = point2d(3,4); +fprintf('(%f, %f)\n',a.x,a.y); +% (3.000000, 4.000000) + +b = a.normalize(); +fprintf('(%f, %f)\n',b.x,b.y); +% (0.600000, 0.800000) +``` + +### 属性 + +可以给属性提供默认值 + +```matlab +classdef point2d + properties + x = cos(pi/12); + y = sin(pi/12); + end + ... +end +``` + +默认值不需要是常量,可以是任何表达式 + +```matlab +classdef demo + properties + time_stamp = date; + end + ... +end +``` + +属性的默认值在类被加载时会被计算,并不会在每一个对象创建时重新计算。 + +可以将属性标记为只读(`Constant`),不允许对其进行修改。 + +```matlab +classdef demo + properties(Constant) + R = pi/180; + end + ... +end +``` + +尝试修改会报错 + +```matlab +s = demo(); +disp(s.R) + +s.R = 100; % error +``` + +### 构造方法和普通方法 + +#### 构造方法 + +与类同名的方法称为构造方法。MATLAB只允许创建一个构造方法,但是我们通过nargin判断参数个数,并据此实现不同的创建行为,例如 + +```matlab +function obj = point2d(x0,y0) + if nargin == 0 + obj.x = 0; + obj.y = 0; + elseif nargin == 2 + obj.x = x0; + obj.y = y0; + else + error("unsupported arguments") + end +end +``` + +例如 + +```matlab +s1 = point2d(1,2); +s2 = point2d(); +s3 = point2d; +``` + +#### 普通方法 + +类的普通方法的第一个参数是对象自身,并且习惯上使用obj表示。 + +```matlab +classdef demo + properties + x = 100; + end + methods + function z = compute(obj,y) + z = obj.x + y; + end + end +end +``` + +普通方法可以通过对象或类调用 + +```matlab +s = demo(); +s.compute(10); % 110 +compute(s,20); % 120 +``` + +### 静态方法 + +MATLAB 提供了静态方法,在定义时标记为 `Static`,静态方法没有`obj`参数,不绑定任何的对象,不能访问类对象的普通属性,但是可以访问类的常量属性。 + +例如 + +```matlab +classdef demo + methods(Static) % 静态方法 + function hello() + disp("hello,world!") + end + end +end +``` + +使用例如 + +```matlab +>> demo.hello() +hello,world! +>> s = demo(); +>> s.hello() +hello,world! +``` + +### 重写disp方法 + +可以通过提供`disp`方法来定制自定义类型调用`disp`函数时的行为,例如 + +```matlab +classdef point2d + properties + x = 0 + y = 0 + end + methods + function disp(obj) + fprintf("(%f,%f)",obj.x,obj.y); + end + end +end +``` + +提供`disp`函数后的输出 + +```matlab +>> s = point2d(); +>> disp(s) + + (0.000000,0.000000) +``` + +作为对比,默认情况下的输出 + +```matlab +>> s = point2d(); +>> disp(s) + point2d with properties: + + x: 0 + y: 0 + R: 0.0175 +``` + +### 重载运算符 + +MATLAB 支持自定义类型对运算符的重载,例如`plus`方法对应加法。 + +```matlab +classdef point2d + properties + x + y + end + methods + function obj = point2d(x0,y0) + % same as before + end + function result = plus(obj, other) + result = point2d(obj.x + other.x, obj.y + other.y); + end + end +end +``` + +例如 + +```matlab +>> a = point2d(1,0); +>> b = point2d(0,2); +>> a + b +ans = + point2d with properties: + + x: 1 + y: 2 +``` + +### 属性和方法的权限 + +MATLAB 提供了比 C++ 和 Java 更加精细的访问权限控制,默认情况下所有的属性和方法都是public。 + +基本的三种权限例如 + +```matlab +classdef demo + properties % public + x1 + end + properties(Access = protected) + x2 + end + properties(Access = privated) + x3 + end + + methods % public + function h1(obj) + end + end + methods(Access = protected) + function h2(obj) + end + end + methods(Access = privated) + function h3(obj) + end + end +end +``` + +MATLAB对属性提供了更精细的访问权限,可以将其拆分为读权限和写权限,例如 + +```matlab +classdef demo + properties(SetAccess = private) + x1 + end + properties(SetAccess = private, GetAccess = protected) + x2 + end +end +``` + +### 类的继承 + +MATLAB 使用 `<` 表示继承关系。 + +基类 + +```matlab +classdef demo + properties + Value + end + methods + function obj = demo(val) + if nargin > 0 + obj.Value = val; + else + obj.Value = 0; + end + end + + function displayValue(obj) + disp(['Value: ', num2str(obj.Value)]); + end + end +end +``` + +派生类 + +```matlab +classdef demo2 < demo + properties + ExtraValue + end + + methods + function obj = demo2(val, extraVal) + obj = obj@demo(val); % 调用基类构造方法 + if nargin > 1 + obj.ExtraValue = extraVal; + else + obj.ExtraValue = 0; + end + end + + function displayValue(obj) + displayValue@demo(obj); % 调用基类的同名函数 + disp(['Extra Value: ',num2str(obj.ExtraValue)]); + end + end +end +``` + +### 补充 + +#### 抽象方法和抽象类 + +MATLAB提供了抽象方法和抽象类。 + +抽象基类(不可实例化) + +```matlab +classdef demo + methods(Abstract) % 抽象方法 + hello(obj) % 只有接口,没有实现 + end +end +``` + +继承自抽象基类的派生类(实现了抽象方法,可以实例化) + +```matlab +classdef demo2 < demo + methods + function hello(obj) % 实现抽象方法 + disp("hello,world!") + end + end +end +``` + +#### 禁止继承和重写 + +可以使用 `Sealed` 关键词来禁止一个类被继承,例如 + +```matlab +classdef (Sealed) demo + ... +end +``` + +可以使用 `Sealed` 关键词来禁止方法被派生类重写,例如 + +```matlab +classdef demo + methods(Sealed) + ... + end +end +``` + 另见 ----