带继承的MATLAB字段访问会修改所有实例吗? [英] MATLAB field access with inheritance modifying all instances?

查看:85
本文介绍了带继承的MATLAB字段访问会修改所有实例吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用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?

推荐答案

您应该在构造函数中初始化nodesfaces属性,而不是将其作为默认属性值.

You should initialise your nodes and faces properties in the constructor, not as a default property value.

那么这是怎么回事?首先要注意的是containers.Maphandle类.

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的副本,并且ab是具有 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的引用,并且ab是具有 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆