Passing on superclass property values to subclass

27 views (last 30 days)
Below I have a superclass called "myclass". Its constructor is written to initialize property 'a' with the 'input' argument, unless this argument is already an object of myclass, in which case it simply returns the object unchanged.
classdef myclass
properties
a=1;
end
methods
function obj=myclass(input)
if isa(input,'myclass')
obj=input; return
else
obj.a=input;
end
end
end
end
Both the following give the desired behavior,
>> objSuper=myclass(2)
objSuper =
myclass with properties:
a: 2
>> objSuper=myclass(objSuper)
objSuper =
myclass with properties:
a: 2
Now, I have a subclass called "mysubclass". Apart from intializing the superclass part of the object, the only desired behavior of its constructor is to modify the superclass property a, multiplying it by 10.
classdef mysubclass < myclass
methods
function obj=mysubclass(input)
obj=obj@myclass(input);
obj.a=10*obj.a;
end
end
end
As with the superclass, I would like the subclass constructor to be able to accept as input either a desired initializing value for 'a', or an object of type myclass itself, and use it accordingly to initialize the super-class part of the object.
The former works as I intend,
>> objSub=mysubclass(2)
objSub =
mysubclass with properties:
a: 20
The latter, however, gives me
>> objSub=mysubclass(objSuper)
When constructing an instance of class 'mysubclass', the constructor must preserve the class
of the returned object.
Error in mysubclass (line 9)
obj=obj@myclass(input);
I don't understand precisely why this error occurs. It appears that the command obj=obj@myclass(input) is somehow deleting the subclass part of 'obj', but as long as obj@myclass returns a valid object of type myclass (which it does), I don't see why the subclass constructor cannot handle that.

Accepted Answer

Matt J
Matt J on 25 Jan 2016
I think what Adam said here is the key:
but it knows it is creating this as part of creating the subclass
In other words, the 'obj' output of the myclass() constructor is not an ordinary output variable. Not only is it pre-initialized when the myclass workspace is entered, but the pre-initialization type also depends on how myclass() was invoked. If it was invoked using a subclass object, as in subclassObj@myclass() then obj is pre-intialized to the subclass type. This is confirmed by the following,
classdef myclass
methods
function obj=myclass
disp ' '
disp(['obj is a ' class(obj) ' object'])
disp ' '
end
end
end
classdef mysubclass < myclass
methods
function obj=mysubclass
obj=obj@myclass;
end
end
end
which gives the behavior:
>> myclass;
obj is a myclass object
>> mysubclass;
obj is a mysubclass object
And therefore, assigning obj a superclass object, even in the superclass constructor, can force it to be the wrong type.
  1 Comment
Matt J
Matt J on 26 Jan 2016
One remedy is to use the copyObject function proposed in this post and modify the myclass() constructor to,
function obj=myclass(input)
if isa(input,'myclass')
obj=copyObject(input,obj);
else
obj.a=input;
end
end

Sign in to comment.

More Answers (2)

Adam
Adam on 25 Jan 2016
Edited: Adam on 25 Jan 2016
A class constructor has some special constraints that other functions do not have. One of these is that it must returned an object of the class whose constructor it is.
You are trying to pass a ready-made object of a subclass into the superclass constructor and, if that is the case rather than you passing in a raw value, you want it to return you your subclass, but this is not possible because the superclass can only return an object of its own class from its constructor, not an object of a class derived from it.
Intuitively even in the first case this looks like something I would not advise doing, but I guess if it works (in the easier first case) it may not be that bad. Since Matlab functions do not allow overloads this would be the only way to allow both a normal constructor and a copy constructor, but I have never tried it (or wanted to!).
Personally I would be tempted to use some other approach than passing in a pre-created object to a class constructor - e.g. a static method on the class that creates the object and then sets properties as required. This should also get around the problem that you do get in the second case. i.e. if you already have an object then avoid even making a call to the constructor - have some wrapper code make the decision whether to call the constructor (to just pass in your value for 'a') or to simply create a copy of the object passed in if that is your goal.
  4 Comments
Adam
Adam on 25 Jan 2016
Edited: Adam on 25 Jan 2016
Actually my original answer was so wrong that had you done what I thought you had done instead your code would have worked for the same reason I corrected myself about in the above post.
I have added a new answer that should be more sensible and basically include what I have added in a comment here. I can then delete this answer if you are happy that my other answer covers what I have said in the comments here.

Sign in to comment.


Adam
Adam on 25 Jan 2016
When creating an object of a subclass this is the object type that must be created in the construction process.
Whether you are constructing the base class part of the object or the derived class part the object type must still be that of the subclass if it is a subclass object you are creating.
Therefore your code hits an error because in the base class (myclass) you try to explicitly create an object of the base class type and assign it to obj. This is not allowed because obj must be of subclass type.
So actually if you were passing your objSub into the constructor instead of objSuper this should work fine because the class type is the expected one so the base class will assign the existing object of type objSub to its 'obj' and return it to the subclass constructor for it to complete construction.

Categories

Find more on Construct and Work with Object Arrays in Help Center and File Exchange

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!