Domande su OOP in MQL5 - pagina 83

 

Yaah... Quanto sono incasinate le persone con const((((.

Per capire i metodi con lo specificatore const

class CTest{
   int i;
public:
   CTest(int _i):i(_i){}
   int Get() const {return i;}
   int Get()   {return 2*i;}
};

void OnStart()
  {
   const CTest a(5);
   CTest b(8);
   Print(a.Get()); //5
   Print(b.Get()); //16
  }

Ora fare

   //int Get() const {return i;}

e poi fare viceversa:

//   int Get()   {return 2*i;}

)))

 
Alexandr Andreev:

Anche una variante dello stesso codice.


È con le costanti.

E sei sicuro che l'input

Compare(CObject const *node,int const mode=0)

♪ you'll always feed ♪

CChartObjectRectangleX*

scrivere senza controllare?

return (  Time(1)-dynamic_cast<const ME*>(node).Time(1));

?

 
Alexandr Andreev:

la variante senza la costituzione, poiché la classe base non ha riferimenti ai parametri di input, funzionerà anche correttamente, sebbene questo stile non sia molto intelligente

Non funzionerà in questo modo. Non è possibile cambiare la firma in Compare. È principalmente necessario per il metodo QuickSort, che è incluso in SB, per farlo funzionare.

Se cambiate la firma, non è un override della funzione virtuale ma un overloading e sta chiamando il metodo della classe base CObject dove ritorna 0;

Naturalmente, questo può essere risolto da wrapper (decorazione) ai contenitori, ma perché questi movimenti inutili, o altrimenti non usare SB e scrivere tutto da zero.

 
Vladimir Simakov:

Sembra essere lo stesso del tuo, solo con meno lettere. Quindi, è una questione di gusti, ma ho rimosso la variabile extra (molto probabilmente, il compilatore l'avrebbe rimossa come parte dell'ottimizzazione).

Per quanto riguarda il mio controllo dei nodi. Deve essere sostituito con CheckPointer(node)==POINTER_INVALID, ma è un overhead - una chiamata di funzione. Anche se è inlined, è comunque almeno dereferenziato e controlla il flag di stato. Se solo library o concrete, avete scritto un programma che userà i metodi Compare, meglio !node e sul codice per guardare se il puntatore non è valido. Se siete troppo pigri per fare attenzione ai puntatori o se è una libreria per sfigati, solo CheckPointer(node)==POINTER_INVALID.

Se rimuovete lo specificatore const che avete evidenziato, non potete chiamare questi metodi da un oggetto costante.

UPD: il controllo evidenziato può essere rimosso, come lo è nei metodi chiamati.

Vladimir, proprio in questo caso CheckPointer è superfluo. dynamic_cast restituirà NULL per qualsiasi cast fallito, anche se il puntatore è rotto. Per favore, correggetemi se mi sbaglio. Testato molto tempo fa, il test ha richiesto 5 secondi).

Meccanismo di funzionamento di CheckPointer (in parole semplici, non sono fluente in termini di basso livello) - cerca per puntatore che tipo di oggetto, dinamico o statico, se non possiamo ottenere informazioni, significa POINTER_INVALID. Questo può essere il caso quando l'oggetto dinamico è stato rimosso, non so altre situazioni, o caricato spazzatura al puntatore, ma deve controllare il compilatore, se non è possibile trovare scappatoie.

e dynamic_cast fa lo stesso, controllando anche se il puntatore può essere castato al tipo richiesto, cioè se è un puntatore di questo tipo o di una classe figlia.

Se il puntatore è rotto, dynamic_cast non riesce a rilevare nulla e restituisce NULL.

Ecco perché non ho usato CheckPointer. Ma di solito uso questo assegno ovunque fuori dal pericolo. Dopo tutto, trovare un errore in un software, che non è caduto, un po' più facile sembra).

E che dire dei non-const - in teoria possiamo avere un metodo come GetRatingByAnyFormula() { m_rating01=Formula01(); return m_rating01;}

sarebbe abbastanza scomodo se non fosse usato subito nell'ordinamento, cioè dovremmo prima contare il punteggio e poi chiamare l'ordinamento in base ad esso. Oppure, come già detto, scrivete il vostro SB da zero).

 
Aleksey Mavrin:

Questo non va bene. La firma non può essere cambiata in Compare. È principalmente allo scopo di far funzionare QuickSort, il metodo di ordinamento regolare incluso in SB.

Se cambiate la firma, non si tratta di un override della funzione virtuale, ma di un overloading e verrà chiamato il metodo della classe base CObject, dove ritorna 0;

Naturalmente, questo può essere risolto da wrapper (decorazione) ai contenitori, ma perché questi movimenti inutili, o non usare SB e scrivere tutto da zero?

Il modo più corretto è quello di non scrivere su µl

 
Aleksey Mavrin:

Vladimir, in questo caso CheckPointer è ridondante. dynamic_cast restituirà NULL per qualsiasi cast non riuscito, anche se il puntatore è rotto. Per favore, correggetemi se mi sbaglio. Testato molto tempo fa, il test ha richiesto 5 secondi).

Meccanismo di funzionamento di CheckPointer (in parole semplici, non sono fluente in termini di basso livello) - cerca per puntatore che tipo di oggetto, dinamico o statico, se non possiamo ottenere informazioni, significa POINTER_INVALID. Questo può essere il caso se l'oggetto dinamico è stato rimosso, altre situazioni non so, o caricato spazzatura al puntatore, ma deve controllare il compilatore, se non si possono trovare scappatoie.

e dynamic_cast fa lo stesso, controllando anche se il puntatore può essere castato al tipo richiesto, cioè se è un puntatore di questo tipo o di una classe figlia.

Se il puntatore è rotto, dynamic_cast non riesce a rilevare nulla e restituisce NULL.

Ecco perché non ho usato CheckPointer. Ma di solito uso questo assegno ovunque fuori dal pericolo. Dopo tutto, trovare un errore in un software, che non è caduto, un po' più facile sembra).

E che dire dei non-const - in teoria possiamo avere un metodo come GetRatingByAnyFormula() { m_rating01=Formula01(); return m_rating01;}

sarebbe abbastanza scomodo se non fosse usato subito nell'ordinamento, cioè dovremmo prima contare il punteggio e poi chiamare l'ordinamento in base ad esso. Oppure potete scrivere il vostro SB da zero, come già detto).

  1. I metodi Compare sono definiti come pubblici, ciò significa che qualsiasi subalterno, non importa quanto duramente si cerchi di spiegarlo nelle specifiche, vi spingerà un descrittore non valido. Naturalmente, se non è una biblioteca, ma solo per te stesso, non devi farlo.
  2. Non so come funziona CheckPointer, c'è fino a . Ma in ogni caso è il clock del processore e l'accesso alla memoria (potrebbe facilmente rivelarsi anche la memoria virtuale).
  3. Sui metodi con lo specificatore const. Se scrivete una libreria, dovete sempre tenere a mente che l'oggetto può avere bisogno di una costante, quindi in quei metodi, che non cambiano lo stato dell'oggetto, come è auspicabile. Finora, però, per quanto mi riguarda, non me ne preoccupo molto.
  4. Scrivendo il proprio sistema, questa è probabilmente la decisione giusta. Questo è solo prospettive interessanti nel rapporto paga/lavoro non è ancora visibile, e quindi non sarà finito, quindi solo per le proprie esigenze).
 
Vladimir Simakov:

Riguardo al mio controllo del nodo. Dovrebbe essere sostituito da CheckPointer(node)==POINTER_INVALID, ma questo è un overhead, una chiamata di funzione.

Il problema non sarà nell'overhead ma nel fatto che un puntatore rotto cambierà la logica del programma. Cioè, invece di rilevare il problema, lo seppellirete ancora più in profondità.

CheckPointer dovrebbe essere usato solo per scopi di debug, o come implementazione di un puntatore debole.

 
Vladimir Simakov:
  1. I metodi di comparazione sono definiti come pubblici, quindi qualsiasi malintenzionato, non importa quanto glielo si dica nelle specifiche, ci infilerà un descrittore non valido (chiamiamo le cose con i loro nomi propri). Naturalmente, se non è una biblioteca, ma solo per te stesso, non devi farlo.
  2. Non so come funziona CheckPointer, c'è fino a . Ma in ogni caso è il clock del processore e l'accesso alla memoria (potrebbe facilmente rivelarsi anche la memoria virtuale).
  3. Sui metodi con lo specificatore const. Se scrivete una libreria, dovete sempre tenere a mente che l'oggetto può avere bisogno di una costante, quindi in quei metodi, che non cambiano lo stato dell'oggetto, come è auspicabile. Finora, però, per quanto mi riguarda, non me ne preoccupo molto.
  4. Scrivendo il proprio sistema, questa è probabilmente la decisione giusta. Questo è solo prospettive interessanti nel rapporto stipendio/lavoro non è ancora visibile, e quindi non ci sarà nulla di finalizzato, quindi solo per le proprie esigenze).

1. Nessuna discussione, ma quello che stavo dicendo è che NON avete bisogno di un CheckPointer (anche per gli underdog), perché dynamic_cast NON può restituire un puntatore non valido, solo NULL.

2. È anche interessante, ma non riesco a pensare immediatamente a un esempio che permetta di ottenere un puntatore non valido se non uccidendo l'oggetto dinamico o "sporcando" la memoria direttamente mentre si lavora su di esso.

Suppongo che ci siano ancora questi modi, ma molto probabilmente si trovano tutti sul piano dell'aggiramento dei controlli del compilatore.

3,4 D'accordo.

P.S.

Devo essermi sbagliato sulla 1a. Il test dice il contrario. Deve essere solo un'impressione).

void OnStart()
  {
      CChartObjectRectangle *base = new CChartObjectRectangle();
      CChartObjectRectangleX *rect = new CChartObjectRectangleX();
       CChartObjectRectangle * dbase  ;
      const CChartObjectRectangleX *drect  ;
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));
      dbase=dynamic_cast< CChartObjectRectangle *>  (base);
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL, " check? ",!dbase," broken? ", EnumToString( CheckPointer(dbase) ));
      delete base;
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));
      dbase=dynamic_cast< CChartObjectRectangle *>  (base);   
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));   
  }
 
È possibile dichiarare un array statico nella sezione pubblica della classe e inizializzarlo nel costruttore? (come sotto) (o solo elemento per elemento?)
 bool Mass[5] = { false, true, false, true, true };
 
Pavel Verveyko:
Un array statico può essere dichiarato nella sezione pubblica della classe e inizializzato nel costruttore? (come sotto) (o solo elemento per elemento?)

Potete inizializzare una matrice locale ed eseguire un ArrayCopy nel campo di matrice appropriato:

class A{
public:
   bool Mass[5];
   A(){
       bool mass_init[5] = { false, true, false, true, true };
       ArrayCopy(Mass, mass_init);
   }
};