2013-04-24 8 views
6

Vorrei sovraccaricare solo un tipo di chiamate subsref (il tipo '()' per una particolare classe e lasciare qualsiasi altra chiamata al sottosistema incorporato di Matlab - in particolare, voglio che Matlab gestisca l'accesso di proprietà/metodo tramite il '' genere. Ma sembra che la funzione 'builtin' di Matlab non funzioni quando subsref è sovraccarico in una classe.Perché non posso usare builtin per le classi che sovraccaricano il sottorequ?

Considerate questa classe:

classdef TestBuiltIn 
    properties 
     testprop = 'This is the built in method'; 
    end 

    methods 
     function v = subsref(this, s) 
      disp('This is the overloaded method'); 
     end 
    end 
end 

di utilizzare il metodo di overload subsref, faccio questo:

t = TestBuiltIn; 
t.testprop 
    >> This is the overloaded method 

Ecco come previsto. Ma ora voglio chiamare il metodo sottosf costruito da Matlab. Per assicurarsi che sto facendo le cose per bene, prima cerco un bando simile su una struttura:

x.testprop = 'Accessed correctly'; 
s.type = '.'; 
s.subs = 'testprop'; 
builtin('subsref', x, s) 
    >> Accessed correctly 

Ecco come previsto pure. Ma, quando provo lo stesso metodo su TestBuiltIn:

builtin('subsref', t, s) 
    >> This is the overloaded method 

... Matlab chiama il metodo di overload, piuttosto che il costruito nel metodo. Perché Matlab chiama il metodo sovraccarico quando ho richiesto che chiami il metodo integrato nel?

AGGIORNAMENTO: In risposta alla risposta di @Andrew Janke, questa soluzione quasi funziona ma non del tutto. Considerate questa classe:

classdef TestIndexing 
    properties 
     prop1 
     child 
    end 

    methods 
     function this = TestIndexing(n) 
      if nargin==0 
       n = 1; 
      end 

      this.prop1 = n; 
      if n<2 
       this.child = TestIndexing(n+1); 
      else 
       this.child = ['child on instance ' num2str(n)]; 
      end 
     end 

     function v = subsref(this, s) 
      if strcmp(s(1).type, '()') 
       v = 'overloaded method'; 
      else 
       v = builtin('subsref', this, s); 
      end 
     end 
    end 
end 

Tutto questo funziona:

t = TestIndexing; 
t(1) 
    >> overloaded method 
t.prop1 
    >> 1 
t.child 
    >> [TestIndexing instance] 
t.child.prop1 
    >> 2 

Ma questo non funziona; Esso utilizza il costruito nel subsref per il bambino piuttosto che il subsref sovraccarico:

t.child(1) 
    >> [TestIndexing instance] 

Nota che il comportamento di cui sopra non è coerente con entrambi questi comportamenti (che sono come previsto):

tc = t.child; 
tc(1) 
    >> overloaded method 

x.child = t.child; 
x.child(1) 
    >> overloaded method 
+0

Non sono sicuro di aver capito completamente, ma penso che prima venga chiamata la funzione integrata, e in quella chiamata viene chiamato il metodo di sovraccarico. Se possibile, inserire un punto di interruzione in un punto utile. –

+0

Qualcosa di completamente diverso: spero che tu provi a farlo per interesse personale, poiché per la maggior parte dei problemi l'overload di subsref potrebbe non essere la soluzione migliore. –

+0

Non sono sicuro di cosa intendi con la funzione incorporata chiamata per prima; se ciò fosse ipotetico (non so come, ma diciamo), penso che avrei bisogno di impostare un punto di interruzione all'interno della funzione subsref incorporata da Matlab per verificare . Ma questa è una funzione nativa piuttosto che una funzione m, quindi non posso mettere lì un breakpoint. – Ben

risposta

4

E 'possibile , IIRC. Per cambiare () ma non {} e '.', Scrivere il metodo subsref per passare gli altri casi al sottosistema incorporato dal sottosistema sovraccaricato, invece di provare a chiamare esplicitamente il builtin dall'esterno.

function B = subsref(A, S) 
    % Handle the first indexing on your obj itself 
    switch S(1).type 
     case '()' 
      B = % ... do your custom "()" behavior ... 
     otherwise 
      % Enable normal "." and "{}" behavior 
      B = builtin('subsref', A, S(1)) 
     end 
    end 
    % Handle "chaining" (not sure this part is fully correct; it is tricky) 
    orig_B = B; % hold on to a copy for debugging purposes 
    if numel(S) > 1 
     B = subsref(B, S(2:end)); % regular call, not "builtin", to support overrides 
    end 
end 

(E se questo builtin chiamata non funziona, si può semplicemente mettere in casi che utilizzano . e {} direttamente, perché il sovraccarico di subsref viene ignorato all'interno della definizione di classe.)

Per rendere perfettamente funzionante, potrebbe essere necessario modificare B in una varargout e aggiungere il comportamento di concatenamento al caso "()".

+0

Grazie, funziona quasi ma non del tutto - si prega di vedere l'aggiornamento nella mia domanda – Ben

+0

Cosa sta succedendo c'è in Matlab, un'espressione con indicizzazione multipla come 'foo.bar.baz (3)', invece di essere valutata in passi come fare 'foo.bar' e quindi passare il risultato a' .baz' e quindi passare quel risultato a '(3)', analizzerà l'intera espressione e la passerà in una singola chiamata a subsref. (Questo non è intuitivo.) Quindi il tuo 'subsref' ha bisogno di guardare S, gestire S (1), e quindi gestire il comportamento" concatenare "passando manualmente i risultati insieme a' S (2: fine) 'insieme ad un'altra chiamata di 'subsref', che quindi raccoglierà il metodo sovraccarico. –

+0

Ho modificato il mio codice di esempio per mostrare il comportamento di "concatenamento". È un po 'complicato e non posso testarlo per correttezza perché non ho Matlab adesso (mi dispiace), ma questo è fondamentalmente ciò che devi fare. –

0

In generale. È necessario utilizzare builtin(m,s) all'interno della funzione che è stata sovraccaricata. Questo è specificato chiaramente nella documentazione di MATLAB.

http://www.mathworks.com/help/matlab/ref/builtin.html

incorporata (funzione, x1, ..., xn) esegue la funzione built con gli argomenti ingresso x1 attraverso xn. Utilizzare built-in per eseguire l'originale integrato da un metodo che sovraccarica la funzione. Per funzionare correttamente con , non devi mai sovraccaricare il built-in.

Considerate questo codice:

classdef TestBuiltIn 
    properties 
     testprop = 'This is the built in method'; 
     testprop2 = 'This is the derived subsref '; 
    end 
    methods 

     function v = subsref(m, s) 
      disp('enter subsref no matter how!'); 
      v = builtin('subsref',m, s); 
     end 
    end 
end 

e test di comando

clear; 
t = TestBuiltIn; 
builtin('subsref', t, s) 
s.type = '.'; 
s.subs = 'testprop'; 
s2 = s; 
s2.subs = 'testprop2'; 

>> builtin('subsref', t, s1) 

enter subsref no matter how! 

ans = 

This is the derived subsref 

>> builtin('subsref', t, s) 
enter subsref no matter how! 

ans = 

This is the built in method 
1

Per espandere sulla spiegazione data sulla Mathworks board, Builtin funziona solo all'interno di un metodo di overload per accedere al pre- metodo esistente (integrato).

sovraccarico di un metodo in Matlab ombre efficacemente il costruito in attuazione da tutto tranne il metodo facendo pedinamento, e il metodo facendo pedinamento devono usare incorporato per accedere costruito in attuazione anziché recursing in sé.

0

Nella versione aggiornata di questo problema, quando si chiama t.child(1), la funzione subsref riceveranno argomento s con s(1).type='.', s(1).subs='child' e s(2).type='()', s(2).subs='1'. La valutazione di questa espressione non è in una procedura dettagliata, come Andrew Janke menzionato nella sua risposta. Di conseguenza, quando si esegue l'override di subsref, è necessario gestire questa catena di operazioni, elaborando prima "." operatore. Ecco un esempio di incompleta per il vostro caso,

function v = subsref(this, s) 
    switch s(1).type 
     case '.' 
      member = s(1).subs; 
      if ismethod(this, member) 
       % invoke builtin function to access method member 
       % there is issue about the number of output arguments 
       v = builtin('subsref',this,s); 
      elseif isprop(this, member) % property 
       if length(s) == 1 
        % invoke builtin function to access method member 
        v = builtin('subsref', this, s); 
       elseif length(s) == 2 && strcmp(s(2).type,'()') 
        % this is where you evaluate 'tc.child(1)' 
       else 
        % add other cases when you need, otherwise calling builtin 
       end 
      else 
       % handling error. 
      end 
     case '()' 
      % this is where you evaluate 't(1)' 
      % you may need to handle something like 't(1).prop1', like the '.' case 
     otherwise 
      % by default, calling the builtin. 
    end 
end 

si possono anche trovare un esempio di codice dettagliato e istruzione a Code Patterns for subsref and subsasgn Methods.

Una cosa di più potrebbe essere necessario sapere, è che metodo membri in questa classe saranno invocati attraverso subsref con '' operazione. Guardate questo argomento subsref on classes: how to dispatch methods?, troverete che la funzione builtin non ha valore di ritorno (poiché il metodo invocato non ha valore di ritorno). Tuttavia, il valore restituito di builtin viene assegnato a v (anche se v è sostituito da varargout), che è un errore evidente. L'autore fornisce anche una soluzione temporanea utilizzando try ... catch per risolvere questo errore.

Problemi correlati