带继承的MATLAB字段访问会修改所有实例吗? [英] MATLAB field access with inheritance modifying all instances?
问题描述
我正在尝试使用MATLAB OOP功能为网格开发数据结构.长话短说,我正在修改一个实例的字段,该实例继承自与另一个实例相同的基类,并且两个实例都在被修改,就像该字段被声明为静态的一样!
I'm trying to develop a data structure for a mesh using the MATLAB OOP functionalities. Long story short, I'm modifying a field from an instance that inherits from the same base class as another instance, and both instances are being modified, as if the field was declared static!
我在MATLAB的抽象基类(m_element)中包含以下代码:
I have this code inside an abstract base class (m_element) in MATLAB:
properties(Access = protected)
nodes = containers.Map('KeyType','int64', 'ValueType', 'any');
faces = containers.Map('KeyType','int64', 'ValueType', 'any');
end
这些字段表示每个元素的连通性.例如,哪些节点是第n个节点的邻居,或者哪些面与第n个节点相邻.
These field represent the connectivity of each element. For example, which nodes are neighbors of the n'th node, or which faces are adjacent to the n'th node.
我还有另外两个类:m_face和m_node,每个类都继承自m_element. m_node非常简单:
I also have two other classes: m_face and m_node, each one inheriting from m_element. m_node is very simple:
classdef m_node < m_element
properties
x = 0;
y = 0;
z = 0;
end
methods
function node = m_node(gmsh_id, x, y, z)
node = node@m_element(gmsh_id);
node.x = x;
node.y = y;
node.z = z;
end
end
end
但是当涉及到m_face时,我遇到了一个问题.这是出现问题的构造函数:
But when it comes to m_face, I'm facing an issue. Here's the constructor, where the problem is arising:
function face = m_face(varargin)
face = face@m_element(varargin{1});
for k = 2:nargin
nod = varargin{k};
if(~isa(nod, 'm_node'))
error('Algum dos argumentos não é um node!');
elseif (~isvalid(nod))
error('Algum dos argumentos não é válido!');
else
face.nodes(nod.gmsh_id) = nod;
nod.faces(face.gmsh_id) = face;
end
end
end
m_face构造函数希望将面部ID作为第一个参数,其余的应该是构成面部的节点. face.nodes(nod.gmsh_id) = nod;
行似乎是造成我的问题的原因.我有一个m_mesh类,它将容纳每个节点和面:
The m_face constructor expects the face ID to come as the first argument, and the rest should be the nodes that forms the face. The line face.nodes(nod.gmsh_id) = nod;
seems to be causing my problem. I have a m_mesh class which shall hold every node and face:
classdef m_mesh < handle
properties(SetAccess = private)
nodes = containers.Map('KeyType','int64', 'ValueType', 'any');
faces = containers.Map('KeyType','int64', 'ValueType', 'any');
end
methods
function theMesh = m_mesh(msh)
for idx = 1:numel(msh.POS(:,1))
n = msh.POS(idx,:);
theMesh.nodes(idx) = m_node(idx, n(1), n(2), n(3));
end
for idx = 1:numel(msh.TRIANGLES(:,1))
ele = msh.TRIANGLES(idx,:);
nod(1) = theMesh.nodes(ele(1));
nod(2) = theMesh.nodes(ele(2));
nod(3) = theMesh.nodes(ele(3));
theMesh.faces(idx) = m_face(idx, nod(1), nod(2), nod(3));
end
end
end
end
构造函数的msh
参数保存节点的空间位置以及组成每个面的节点(在这种情况下为三角形).
The msh
argument to the constructor holds the nodes spatial positions, and also the nodes that composes each face (which in this case are triangles).
这是构建网格时得到的:
Here's what I get when I build the mesh:
>> mesh = m_mesh(m)
mesh =
m_mesh with properties:
nodes: [5x1 containers.Map]
edges: [0x1 containers.Map]
faces: [4x1 containers.Map]
>> nod = mesh.nodes.values();
>> nod{1}.i_nodes
ans =
[1x1 m_node] [1x1 m_node] [1x1 m_node] [1x1 m_node] [1x1 m_node]
i_nodes返回实例映射值.现在,那怎么可能?如果我尚未设置第一个(以及所有其他节点!)节点,为什么还有五个相邻节点?当我从随机实例访问此字段时,为什么MATLAB应该为所有实例和所有子类更改一个非静态字段?
The i_nodes returns the instance map values. Now, how's that possible? Why does my first (and all the others!) node have FIVE adjacent nodes, if I haven't set this yet? Why should MATLAB change an non-static field for all instances and all subclasses when I access this field from a random instance?
推荐答案
您应该在构造函数中初始化nodes
和faces
属性,而不是将其作为默认属性值.
You should initialise your nodes
and faces
properties in the constructor, not as a default property value.
那么这是怎么回事?首先要注意的是containers.Map
是handle
类.
So what's going on here? The first thing to note is that containers.Map
is a handle
class.
MATLAB中的普通变量具有 value 行为:
Normal variables in MATLAB have value behaviour:
>> a = 1;
>> b = a;
>> a = 2;
>> b
b =
1
请注意,当您更改a
时,b
并未更改-它是a
的副本,并且a
和b
是具有的 value 变量按值传递行为.
Note that b
has not changed when you changed a
- it is a copy of a
, and a
and b
are value variables that have pass-by-value behaviour.
其他一些变量具有 handle 行为:
Some other variables have handle behaviour:
>> a = figure;
>> b = a;
>> get(a, 'Name')
ans =
''
>> get(b, 'Name')
ans =
''
>> set(a, 'Name', 'hello')
>> get(b, 'Name')
ans =
hello
请注意,当您更改a
时,b
也已更改-它是对a
的引用,并且a
和b
是具有 pass的 handle 变量. -按引用行为.
Note that b
has changed when you changed a
- it is a reference to a
, and a
and b
are handle variables that have pass-by-reference behaviour.
containers.Map
变量是句柄变量.
第二点要注意的是,属性默认值是在第一次实例化该类时一次 求值的. (如果用clear classes
清除了类定义,则在下次实例化它时将再次对其求值).每次创建对象时,都不会对它们进行评估.
The second thing to note is that property default values are evaluated once, at the first time the class is instantiated. (If you clear the class definition with clear classes
, it will be evaluated again subsequently when you next instantiate it). They are not evaluated every time you create an object.
所以发生的事情是,第一次创建对象时,将实例化该类,对containers.Map
进行求值,之后的每个对象都将 same containers.Map
作为其属性.由于它是一个句柄变量,因此您在一个对象中对属性所做的更改将在其他对象的属性中引用.
So what's happening is that the first time you create an object, the class is instantiated, the containers.Map
is evaluated, and each object after that is getting the same containers.Map
as its property. Since it's a handle variable, changes that you then make to the property in one object are referenced in the properties of others.
您不想要这样:相反,您应该在类构造函数中初始化值.然后,每次构造一个对象时,它将分别进行评估,并且每个对象都将得到一个单独的对象.
You don't want that: instead, you should initialise the values in the class constructor. Then it will get evaluated separately each time you construct an object, and each will get a separate one.
这种行为(即,当您将句柄变量作为属性默认值时)可能会造成混淆,但我认为这是正确的行为-已记录在案,尽管我认为可以更清楚地标出路标.这是文章,其中讨论了该主题-评论,这个问题在作者,我本人和负责OO语法和设计的MathWorks开发人员之间进行了辩论.
This behaviour (i.e., when you have handle variables as property defaults) can be confusing, but I think it's the right behaviour - it is documented, although I think it could be more clearly signposted. Here's an article where the topic is discussed - in the comments, the issue is debated between the author, myself, and a MathWorks developer responsible for OO syntax and design.
这篇关于带继承的MATLAB字段访问会修改所有实例吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!