Errori, bug, domande - pagina 1206

 
stringo:

Proprio così. La priorità è data alla corrispondenza esatta. Ed è davvero giusto.

Perché avete bisogno di questa unificazione? Unificazione dell'elaborazione di programmi progettati in modo errato

L'unificazione è necessaria affinché lo stesso codice funzioni ugualmente con C++ e MQL. In C++, questo ordine è fatto (!) per una ragione (altrimenti ci sono ambiguità ad un certo punto). Originariamente pensavo che il compilatore C++ avesse un'illogicità e/o addirittura un bug, ma ora sono incline a credere che ci siano ragioni oggettive per un tale approccio. Ecco un esempio in MQL, che mostra che X:: g è una corrispondenza completa, ma Y::g viene chiamato comunque - come in C++, il che contraddice l'esempio precedente https://www.mql5.com/ru/forum/1111/page1223#comment_1074757

class A {};
class B : public A {};
class C : public B {};
class X {
public:
        virtual int g( C* c1, C* c2 ) { return ( 1 ); } //полное совпадение здесь
        virtual int g( C* c,  B* b )  { return ( 2 ); }
};
class Y : public C { //здесь ошибся, должно быть public : X
public:
        virtual int g( A* a, B* b ) { return ( 3 ); }
};
void OnStart()
{
        C* c = new C;
        Y* y = new Y;
        Print( y.g( c, c ));
}

Risultato: 3

Si scopre che C++ ha un ordine "illogico" ma non ambiguo, mentre MQL ha un ordine casuale - se c'è una corrispondenza esatta di tipi, una classe base viene chiamata in un caso e una classe derivata nell'altro

 
A100:

L'unificazione è necessaria affinché lo stesso codice funzioni ugualmente con C++ e MQL. In C++, questo ordine è fatto (!) per una ragione. Originariamente pensavo che il compilatore C++ avesse un'illogicità e/o addirittura un bug, ma ora sono incline a credere che ci sia una ragione oggettiva per tale approccio. Ecco un esempio in MQL che mostra che X:: g è una corrispondenza completa, ma Y::g viene chiamato comunque - come in C++, il che contraddice l'esempio precedente

Risultato: 3

Si scopre che C++ ha un ordine "illogico" ma non ambiguo, mentre MQL ha un ordine casuale - quando i tipi corrispondono esattamente, la classe base viene chiamata in un caso e una classe derivata in un altro.

Di quale implementazione C++ stai parlando esattamente? Quanto bene questa implementazione corrisponde allo standard C++. Cosa dice lo standard C++ sulla scelta delle funzioni sovraccaricate?

In realtà, il sovraccarico di funzioni che descrivi è una conseguenza di una progettazione errata.

Il porting del codice sorgente è un mito. Solo il programma di prova funziona allo stesso modo in diversi ambienti C++. Il programma reale (stiamo parlando di migliaia di righe di codice con un valore applicativo reale) funzionerà in modo diverso almeno per alcuni aspetti in ambienti diversi. E non si parla affatto di unificare MQL con C++ - è uno spreco del patrimonio genetico...

 
A100:

L'unificazione è necessaria affinché lo stesso codice funzioni ugualmente con C++ e MQL. In C++, questo ordine è fatto (!) per una ragione (altrimenti ci sono ambiguità ad un certo punto). Originariamente pensavo che il compilatore C++ avesse un'illogicità e/o addirittura un bug, ma ora sono incline a credere che ci siano ragioni oggettive per un tale approccio. Ecco un esempio in MQL, che mostra che X:: g è una corrispondenza completa, ma Y::g viene chiamato comunque - come in C++, il che contraddice l'esempio precedente https://www.mql5.com/ru/forum/1111/page1223#comment_1074757

Risultato: 3

Si scopre che C++ ha un ordine "illogico" ma non ambiguo e MQL ha un ordine casuale - in caso di corrispondenza esatta dei tipi, una classe base viene chiamata in un caso e una classe derivata in un altro caso

Sembra che ti sbagli in questo esempio, se la classe Y è ereditata da X e non da C, allora il comportamento sarebbe lo stesso dell'esempio precedente.
 
stringo:

Cosa dice lo standard C++ sull'ordine di selezione delle funzioni sovraccaricate?

Per citare Strawstrup: "C++ richiede un'esatta corrispondenza di tipo tra la funzione virtuale nella classe base e la funzione sostituita nella classe derivata".

Ora ho esaminato il problema e sono giunto alla conclusione che C++ è corretto. In entrambi gli esempi precedenti, g() della classe derivata nasconde (piuttosto che sostituire) g() della classe base. E il meccanismo di virtualità si attiva solo quando avviene la sostituzione, e la sostituzione richiede una corrispondenza esatta del tipo (eccetto per il tipo di ritorno). Solo la precisione del tipo di ritorno può dipendere dalla particolare implementazione.

 
mql5:
Sembra che ti sbagli in questo esempio, se la classe Y è ereditata da X piuttosto che da C, il comportamento sarebbe lo stesso dell'esempio precedente.

Sì, mi sono sbagliato qui, quindi si scopre che sia C++ che MQL hanno ordini di sostituzione e occultamento non ambigui, ma diversi. Si prega di vedere le mie argomentazioni nel post precedente sulla differenza tra sostituzione e occultamento

Il fatto che il C++ generi un avvertimento quando si nasconde vi dice che questo ordine è scelto intenzionalmente

class A {};
class B : public A {};

class X {
public:
        virtual int g( A* a )
        virtual int f( B* a )
};
class Y : public X {
public:
        virtual int g( A* a ) //подмена  X::g
        virtual int f( A* a ) //сокрытие X::f
};
 
A100:

Sì, mi sono sbagliato qui, quindi si scopre che sia C++ che MQL hanno ordini di sostituzione e occultamento non ambigui, ma diversi. Si prega di vedere le mie argomentazioni nel post precedente sulla differenza tra sostituzione e occultamento

Il fatto che il C++ generi un avvertimento quando si nasconde indica che questo ordine è scelto intenzionalmente

Il compilatore MQL quando cerca un metodo (funzione) non considera il passaggio a un genitore come un casting, come sembra fare con C++ di MS, per esempio.

Grazie per il post, ne discuteremo.

 
mql5:
Il compilatore MQL quando cerca un metodo (funzione) non considera il passaggio a un genitore come un casting, come sembra fare con MS C++ per esempio.

Grazie per il messaggio, ne discuteremo.

Notate che non solo da MS - ho usato Borland C++ 5.5.1

Stroustrup scrive che altrimenti ci possono essere conseguenze spiacevoli legate ad "andare oltre la fine dell'oggetto classe"

 
A100:

Per citare Strawstrup: "C++ richiede un'esatta corrispondenza di tipo tra la funzione virtuale nella classe base e la funzione sostituita nella classe derivata".

Ora ho esaminato il problema e sono giunto alla conclusione che C++ è corretto. In entrambi gli esempi precedenti, g() della classe derivata nasconde (piuttosto che sostituire) g() della classe base. E il meccanismo di virtualità si attiva solo quando avviene la sostituzione, e la sostituzione richiede una corrispondenza esatta del tipo (eccetto per il tipo di ritorno). Solo la precisione del tipo di ritorno può dipendere dalla particolare implementazione.

Aspetta un attimo, aspetta un attimo. Stiamo parlando di sovraccarico di funzioni con parametri diversi.

Le funzioni virtuali, invece, hanno sempre parametri dello stesso tipo. Le funzioni virtuali sono al di fuori dello scopo di questa discussione

 
A100:

Notate che non solo da MS - ho usato Borland C++ 5.5.1

Stroustrup scrive che altrimenti ci possono essere conseguenze spiacevoli legate al "superare la fine dell'oggetto classe"

Ne abbiamo discusso; non abbiamo intenzione di cambiare il comportamento del compilatore MQL - è un "bastone a due tagli". Lasciatemi spiegare.

Il problema è rilevante solo quando si fanno modifiche alle classi pronte (in un programma di lavoro).
Dopo che il genitore ha una funzione più adatta, il programma smetterà improvvisamente di funzionare, perché invece del metodo del discendente è stato chiamato il metodo del genitore.
Bene, se cambiamo il comportamento di MQL, allora può verificarsi una situazione simile - quando si aggiunge un nuovo metodo al discendente, invece della funzione genitore (senza casting dei parametri) viene chiamato il metodo discendente, e con casting dei parametri, e il programma smette di funzionare di nuovo.

Così, non si risolvono altri problemi oltre alla compatibilità con C++, inoltre, il cambiamento del comportamento del compilatore influenzerà i programmi MQL esistenti.
 

Так как переменные типа структур и простых типов не имеют указателей, то применять к ним функцию GetPointer() запрещено.

È anche proibitopassare un puntatorecome argomento a una funzione (quale ???GetPointer o qualsiasi ?).In tutti questi casi, il compilatore segnalerà un errore.

Citazione dalla documentazione.

class A{
public:
   void operator= (const A* from){
      if (GetPointer(this) == GetPointer(from))      // а тут я передаю и все ок
         Alert(1);                                  // резутат 1  из за того что передаю this
      else
         Alert(2);
   }
};

class B : public A{
public:
   void operator= (const B& from){  
      if (GetPointer(this) == GetPointer(from))
         return;
      operator=((A*)(GetPointer(this)));
   }
};
  B b;
   B bb;                        // забыл написать создание объектов и вызов функции.
   b = bb;

Ho già capito perché non rimprovera gli avvisi - è colpa mia che ho passato un puntatore sbagliato in una funzione.