I am trying to create an array of objects of a class Cell in another class Systemin MATLAB. The classCell` is:
classdef Cell
properties
ID;
EntityID;
ZoneID;
NeighborID;
State;
nextChangeTime;
end
methods
% Define the constructor
function obj = Cell()
obj.ID = zeros(1);
obj.EntityID = zeros(1);
obj.ZoneID = zeros(1);
obj.NeighborID = zeros(1);
obj.State = zeros(1);
obj.nextChangeTime = zeros(1);
end
end
Now I have another class System. I try to make an array of Cell objects like this:
classdef System
properties
Cells;
end
methods
function obj = System(dimx,dimy)
obj.Cells(dimx,dimy) = Cell();
end
end
But I think I am using the wrong format. Not sure if this is possible. Any suggestions on how to accomplish this would be appreciated.
In order to be able to create arrays of objects of user-defined class (e.g. Cell class), it is convenient to have the default constructor for the user-defined class. The default constructor is the one that takes no arguments (i.e. when nargin==0). When creating arrays, the implicit initialization of the array's objects is done by this constructor. If this constructor is missing, trying to build arrays by "extending" a scalar object will generate an error.
Another way of creating arrays of objects (without defining a default constructor) is by using horzcat, vertcat and cat.
Aaaaand... when accessing the properties of an object, don't forget to mention the object you're accessing:
obj.Cells = Cell.empty(0,0); % Force the type of empty Cells to Cell class
obj.Cells(dimx,dimy) = Cell();
Related
I've made a mistake and recorded a bunch of important data using a class definition that I can't find anymore. The methods are not important, I just want the data; a struct conversion would be fine.
Is there any way I can recover this?
Googling it did not help.
The solution is to create a new class that overloads the loadobj method. See here for more information regarding the load process for classes.
I replicated your problem by creating a class:
classdef myclass
properties
Prop1
Prop2
Prop3
end
methods
function obj = myclass(a,b,c)
obj.Prop1 = a;
obj.Prop2 = b;
obj.Prop3 = c;
end
end
end
Then I created an object of this class and saving it to a file "x.mat":
x = myclass('a',56,[1,2,3]);
save x
Next, I deleted the myclass file and did clear classes. This put me in your situation.
I then created a new myclass class that overloads the loadobj method:
classdef myclass
properties
data
end
methods (Static)
function obj = loadobj(s)
obj = myclass;
obj.data = s;
end
end
end
Note how it doesn't know any of the original properties. This does not matter. If any of the original properties is missing when loading an object from a MAT-file, loadobj will be called with s being a struct containing all the properties of the original object.
With this new class definition, load x created an object x of class myclass, where x.data was a struct containing the properties of the object saved in "x.mat".
I have an class called TestData that houses a private property called data, which I define as a numeric array. Its goal is to take in data from various other .m files and extract the data and place it in the specified format (numeric array. So, a random_data.m file that I am currently working with spits out a 1X13 double array called Avec. I generate and instance of the class myTestData = TestData(); however, because the member variables are private I need to have getData and setData functions. The only idea I have is to pass Avec into getData (e.g. myTestData.getData(Avec)) and then store it in a temporary array that could then be used by setData to write into data; but I feel like this is bad practice as that array would need to be public. Also, would it make sense to pass the entire array in or should I pass each element in individually. I would like to have it check the data to make sure that it is in proper format, as well.
I guess in general my concept of how the class works in MATLAB may be flawed.
Thanks for your help in advance and if there is anything else that I can provide, please let me know. Below is some code. The first snippet above the class is from the separate .m file.
%Write data to file using the TestData Object
Avec = [some 1X13 double array]
myTestData=TestData; % Generate an instance of the object
myTestData.getData(Avec);
classdef TestData
properties (Access = private)
metaData % stores meta data in Nx2 array
data % stores data in PxQ array
colLabels % labels columns
colUnits % provides units
metaPrint % used to print metaData
temp % debugging purposes only
end
methods
%****************************************************************************%
%Function: TestData
%Purpose: Constructor used to allocate data arrays
%****************************************************************************%
function this = TestData() %constructor
this.metaData = [];
this.data = [];
this.colLabels = [];
this.colUnits = [];
this.metaPrint = [];
this.temp = [];
end %TestData()
%%
%****************************************************************************%
%Function:
%Inputs:
%Purpose:
%****************************************************************************%
function this = getData(this, someArray)
????
end %getData
I think you're misunderstanding the idea of getters and setters. A get function is designed to take something from the object and return it, while a setter is designed to put something into a property of the object. You would want something like:
function data = getData(this)
data = this.data;
% Do any processing to put data into a different format for output
end
function this = setData(this, data)
% Check the data input to make sure it is the right format, etc.
this.data = data;
end
You may also want to design setData to take different types of arguments, like a file name that it can use to load the matrix itself. You could also design your constructor to accept a matrix or file name and initialize data as well.
Also, as Cris alludes to in his comment, if the reason you were making data private was to control how the user could access and modify it, it's enough to just have getters and setters. You can make data public and your property access methods will still be called when accessing the object like Avec = myTestData.data or myTestData.data = Avec.
My Objective is:
Using MATLAB, set the property value within one class method, and the property values are different between instances.
My Problem is:
When using SET in the class method, I will change the property value of all instances of this class, which is not what I want. I only want to change the property value of this instance.
About the dynamic property: I think it's used to create a unique property of the instance instead of setting the unique value of a general class property, is that right?
Code example:
classdef Storage
properties
tree = containers.Map('KeyType','int32', 'ValueType','any')
end
methods
function obj = set_tree(obj,period, value)
obj.tree(period) = value;
end
end
end
When setting the value using this method:
st1 = Storage();
st2 = Storage();
st1 = st1.set_tree(10,1);
st2 = st2.set_tree(10,2);
Right now, the value set to st2.tree(10) will override the value set to st1.tree(10), which I am trying to avoid.
The problem you're having is caused by setting a handle class object as a default value for a class property. The relevant documentation says this:
MATLABĀ® evaluates property default values only once when loading the class. MATLAB does not reevaluate the assignment each time you create an object of that class. If you assign an object as a default property value in the class definition, MATLAB calls the constructor for that object only once when loading the class.
So, for your Storage class above, all of your instances will be using the same default containers.Map object stored in the tree property. And since the containers.Map class is a subclass of the handle class it has reference behavior, which means the copies of the object will all point to the same underlying key/value map. If you want independent objects for each instance, you can initialize the tree property in the constructor:
classdef Storage
properties
tree
end
methods
function obj = Storage()
obj.tree = containers.Map('KeyType','int32', 'ValueType','any');
end
function obj = set_tree(obj, value, period)
obj.tree(period) = value;
end
end
end
I am working with a custom defined class I called "PathObj_Standard". I want to make sure that when I load this class, if the property CalcDate was saved as a cell array it is converted to a standard array. However, I changed the class definition some time ago, so when I use the loadobj function, I am getting a struct instead of an object. The original code I'm using has a lot more properties, so I'd rather not create a new object by assigning property by property from the struct to a new object. Furthermore, I'm also hesitant to change the constructor to accept a struct as an argument.
I tried using the class function inside loadobj, but I am getting a Cannot redefine class 'PathObj_Standard' without a call to 'clear classes' error. Isn't this function supposed to force conversion of a struct to an object? Why doesn't it work within the loadobj function?
classdef PathObj_Standard < handle
properties (SetAccess = protected)
CalcDate;
Name;
end
methods(Static)
function obj=loadobj(s)
if isstruct(s)
obj=class(s,'PathObj_Standard');
else
obj=s;
end
if not(isempty(obj.CalcDate)) && iscell(obj.CalcDate)
obj.CalcDate=cell2mat(obj.CalcDate);
end
end
end
methods
function obj=PathObj_Standard(Name,CalcDate)
obj.Name=Name;
obj.CalcDate=CalcDate;
end
end
The issue is that calling class attempts to create a class which you can't do from within your loadobj. You'll want to call the actual constructor
Also in my experience, the easiest way to construct a class from a struct is to inherit from hgsetget rather than handle as that automatically has the set and get methods of MATLAB's graphics objects and these methods can accept property/values in the form of a struct. In newer versions of MATLAB, you can also use the SetGet mixin
classdef PathObj_Standard < hgsetget
If you do this, you could change your loadobj method to be something like
function obj = loadobj(s)
% Update the input struct as needed
if isfield(s, 'CalcDate') && ~isempty(s.CalcDate) && iscell(s.CalcDate)
s.CalcDate = cell2mat(s.CalcDate);
end
% Call the default constructor
obj = PathObj_Standard();
% Update all properties that were supplied to loadobj
set(obj, s)
end
I have an object from my own class object that inherits from my own class data and my own class graphic in MATLAB. To represent the object object, it uses properties and methods from the data-superclass. Now I want to draw my object object with methods from the graphic-superclass, but the methods in this superclass don't know anything about its object-subclass.
Is there a way to give the required data, that is stored in the object-subclass, to the graphic-superclass without putting this information into a function argument like object.draw(this_data_stuff) with the method drawfrom the graphic-superclass and the data this_data_stuff from the object-subclass?
The only way I figured out is to store the subclass object object as property in the graphic-superclass, but it seems odd to store a subclass-object as property in a superclass-object, while the subclass inherits from the same superclass.
EDIT:
data-class:
classdef data < handle
properties
data_stuff
end
methods
function obj = data
end
function obj = compute(obj)
obj.data_stuff = ... % math
end
end
end
graphic-class:
classdef graphic < handle
properties
end
methods
function obj = graphic
end
function obj = draw(obj)
plot(obj.data_stuff,t) % ERROR, property 'data_stuff' is unknown
end
end
end
object-class:
classdef object < data & graphic
properties
end
methods
function obj = object
end
end
end
Test:
object_A = object; % creates object
object_A.compute; % generates data_stuff
object_A.draw; % draws data_stuff, Error here, because 'draw` needs access to the 'data_stuff'-property.