How to call sub or superclass constructor when recursively creating objects
    8 views (last 30 days)
  
       Show older comments
    
Hi,
I'm writing a tree class. I'd like a superclass to contain generic construction / maintenance methods, then be able to subclass it for a range of different, more specific purposes.
Something like:
classdef SuperTree < handle
    properties
      BranchLocation
      Parent
      Children
    end
    methods
      function obj = SuperTree(varargin)
        % construct the the object
      end
      function subdivide(obj, limit_criterion)
        % Lots of code that's difficult to maintain and 
        % shouldn't be overloaded in a subclass
        if limit_criterion
          % Create child branches
          chld1 = SuperTree(args);
          chld2 = SuperTree(args);
          obj.Children = [chld1; chld2]
      end
    end
  end
The problem is that if I create a subclass, then the subdivision method still makes a call to SuperTree() to construct its children.
Is there a way of getting (say) a handle to the constructor function of the current object? I don't want to be overloading the subdivide method for each of my subclasses. Something like this would be ideal:
      function subdivide(obj, limit_criterion)
        % Lots of code that's difficult to maintain and 
        % shouldn't be overloaded in a subclass
        if limit_criterion
          % Create child branches
          chld1 = obj.Constructor(args);
          chld2 = obj.Constructor(args);
          obj.Children = [chld1; chld2]
      end
At the moment I'm working around this with a small utility method, that I overload in each subclass. Working? Yes. Elegant? No. So I'd be interested in any 'proper' solutions.
Thanks!
Tom
3 Comments
  per isakson
      
      
 on 30 Aug 2016
				@Guillaume, which problems do you see in using class(obj) in this context?
This "small utility method" does it contain expressions like chld=Tree(args);?
  Guillaume
      
      
 on 30 Aug 2016
				I don't see any problem in using class(obj). It works fine. It's probably because I come from C++ where reflection does not exist that I find it inelegant. It's probably irrational
If I understood correctly (and the way I'd do it), the small utility method is a one-liner method that is overloaded in each class and just call the class constructor:
classdef SuperTree < handle
    %... props definition  
    methods
        function obj = SuperTree(varargin)
          % construct the the object
        end
        function subdivide(obj, limit_criterion)
          % Lots of code that's difficult to maintain and 
          % shouldn't be overloaded in a subclass
          if limit_criterion
            % Create child branches
            chld1 = NewMe(args);
            chld2 = NewMe(args);
            obj.Children = [chld1; chld2]
        end
       %small utility function to be overloaded in each subclass
       function this = NewMe(args)
           error('Must be overloaded by children');
           this = SuperTree(args);
      end
    end
  end
and child
classdef Child < SuperTree
    %... props definition  
    methods
        function obj = Child(varargin)
          % construct the the object
        end
       function this = NewMe(args)
           this = Child(args);
      end
    end
  end
Answers (1)
  per isakson
      
      
 on 28 Aug 2016
        
      Edited: per isakson
      
      
 on 30 Aug 2016
  
      I think, I understand and that it's doable. Replace
chld1 = obj.Constructor(args);
by
str   = class( obj );
chld1 = feval( str, args );
And in the constructor of the subclass
obj@SuperTree( arguments )
Whether this is the proper way, I don't know.
 
ADDENDUM 2016-08-29 in response to the comment:  "2. this will eliminate any possibility for code generation."
Would this allow code generation? Replace
chld1 = feval( str, args );
by
chld1 = TreeFactory( str, args );
where the simplest form of TreeFactory is an ordinary function
function  tree = TreeFactory( str, args )
    switch str
        case 'oak', tree = Oak( args );
        otherwise
    end
end
3 Comments
  per isakson
      
      
 on 28 Aug 2016
				
      Edited: per isakson
      
      
 on 28 Aug 2016
  
			There has been complains regarding the performance of MATLAB OOP. However, its improving. I've learned to avoid solutions with thousands of simple objects.
"feval() is likely to be quite slow"   Based on some simple tests (R2016a) I don't think so. (That is, it's not slow compared to other ways to create objects in Matlab.)
"will eliminate any possibility for code generation"   Yes.
Given the superclass, handle, I cannot think of any other approach. Or maybe, see Clone Handle Object - using MATLAB OOP by Bobby Nedelkovski
See Also
Categories
				Find more on Construct and Work with Object Arrays in Help Center and File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!