Newsgroup: it.comp.lang.c++
Titolo: Override e argoment default

Allora supponiamo che:
struct A
{
  void foo(int a1);
};
struct B : public A
{
  void foo(int a1, int b=0);
};
E' corretto affermare che B::foo è un override di A::foo in quanto 
"internamente" il compilatore è come se generasse un metodo foo con un 
parametro che chiama la versione a due parametri con 0 nel secondo:
B::foo(int a1)
{
  foo(a1, 0);
}
Dico bene?


Per ora mi "autorispondo":
stando ai miei esperimenti sembra che la risposta corretta sia NI!
Mi spiego meglio:
#include <iostream>
using namespace std;
struct A
{
  void foo(int a1) { cout << "A::foo(" << a1 << ")" << endl; }
  virtual void vfoo(int a1) { cout << "A::foo(" << a1 << ")" << endl; }
};
struct B : public A
{
  void foo(int a1, int b=0) { cout << "B::foo(" << a1 << "," << b << ")" 
<< endl; }
  virtual void vfoo(int a1, int b=0) { cout << "B::foo(" << a1 << "," << 
b << ")" << endl; }
};
int main(int argc, char* argv[])
{
  B b;
  b.foo(15);
  A* pa;
  pa = &b;
  pa->vfoo(15);
  return 0;
}
stampa:
B::foo(15,0)
A::foo(15)
Da questo esempio direi che è sbagliato parlare di overriding vero e 
proprio in quanto la chiamata virtuale non funziona.
Tuttavia un pariziale overriding da qualche parte ci deve essere, in 
quanto la chiamata non virtuale b.foo(15) chiama il metodo con due 
argomenti.
Che ne dite?

 A::foo(15)
   A::vfoo(15)

 parametro che chiama la versione a due parametri con 0 nel secondo:
Direi di no.
E' come se il compilatore aggiungesse il parametro 0 ad ogni chiamata di 
foo.
Quindi ogni chiamata di tipo B::foo(int) viene sostituita con una 
chiamata di tipo B::foo(int, int), che non e' un override di A:foo(int).
Per esempio, scrivendo:
   B b;
   b.foo(3);
viene generato lo stesso codice che si otterrebbe scrivendo:
   B b;
   b.foo(3, 0);
Invece, avendo:
   struct A { virtual void foo(int a1, int a2); };
   struct B: A { void foo(int b1, int b2 = 0); };
se si scrive:
   B b;
   b.foo(3);
   A &a = b;
   a.foo(4, 5);
si chiama prima B::foo(3, 0) e poi B::foo(4, 5).
-- 
     Carlo Milanesi
 
http://digilander.libero.it/carlmila

 argomenti.
Nessun overriding. Chiama quel metodo perché è l'unico metodo che esiste 
ed è visibile in B con quel nome e quei parametri. Il metodo con un 
parametro solo viene ereditato ma è hidden (stessa cosa per vfoo, anche 
se è virtuale).
Nel tuo codice non esiste ne overriding ne overloading.

 
Il concetto di metodo "hidden" mi manca.
Tuttavia credo che intendiamo la stessa cosa:
il metodo della classe base che è stato "sovrascritto", diventa 
ovviamente "nascosto" (in quanto non invocabile attraverso la classe 
derivata).

 assume una nuova implementazione.
Non è vero fino in fondo. L'override si ha anche in assenza di funzioni 
virtuali. E' sufficiente l'ereditarietà.
Per es. considera
template <class T>
void g(T& t) {}
class A
{
   public:
     void f() {}
};
class B : public A
{
   public:
     void f() {}
};
g(A());
g(B());
Se vuoi chiamiamolo pseudo-overriding, ma molti lo ritengono overriding 
vero e proprio.
Kiuhnm

 metodi di una classe base. virtuale o no non c'entra nulla!
Non confondere "to override" con "to overwrite".
Kiuhnm


Il significato di override č "scavalcare" ovvero "non tener conto".
Nel contesto del c++, un metodo di una classe derivata č un override 
rispetto ad un metodo di una classe base quando "viene eseguito al posto 
di".
In questo contesto il termine "sovrascrivere" mi sembra non solo 
appropriato, ma anche uno dei piů corretti che si possano utilizzare.
Googlare "override sovrascrivere" per credere :)
Resta il fatto (come giustamente facevi notare nell'altro post) che 
override non c'entra nulla con metodi virtuali. Override si usa tutte le 
volte che una implementazione specifica ne "sovrascrive" (o ne 
"scavalca" se preferisci) una di base.

 
Ma secondo me basta anche meno:
Ad esempio si parla di "operator new overriding"

 appropriato, ma anche uno dei più corretti che si possano utilizzare.
No, è palesemente errato.
Considera il seguente esempio.
 >>>>
#include <iostream>
using namespace std;
class A
{
public:
	void f() { cout << "A::f()" << endl; }
};
class B : public A
{
public:
	void f() { cout << "B::f()" << endl; }
};
int main()
{
	B b;
	b.f();
	b.A::f();
}
<<<<
Kiuhnm

 Ad esempio si parla di "operator new overriding"
A questa stregua, è tutto overriding.
Ogniqualvolta si sostituisce un componente preesistente con un 
componente proprietario, si sta fancedo dell'"overriding".
Kiuhnm

 Kiuhnm
Cosa dovrebbe dimostrare questo esempio?
b.f(); // produce B::f()
b.A::f(); //produce A::f()
L'unica cosa che vedo č che il metodo f della classe derivata B 
sostituisce, quindi sovrascrive il metodo f della classe base A.
Tant'č che per chiamare la versione di f ereditata dalla classe A devi 
qualificare.
Se tu questo non lo chiami "sovrascrivere", trovami un verbo piů 
appropriato.
Tra parentesi credo di non essere l'unico a pensarla cosě:
http://www.google.it/search?hl=it&rls=GGLD%2CGGLD%3A2004-37%2CGGLD%3Ait&q=override+sovrascrivere+&meta=

 
Di getto mi verrebbe da rispondere SI, tuttavia ho trovato questa 
definizione di Stroustrup
http://www.research.att.com/~bs/glossary.html#Goverriding
che taglia la testa al toro:
secondo BS si parla di overriding solo sulle funzioni virtuali (quindi 
aveva ragione Analog)
Un po piů "elasticamente" č correntemente usato il termine "override" 
anche per normali metodi o per funzioni globali (tipo new), e 
personalmente mi trovo d'accordo con questa visione piů ampia.

 
In effetti più vado a fondo più mi accorgo che ho sempre usato 
indistintamente "override" al posto di "redefinition".
Ho trovato questa distinzione che mi sembra corretta:
a) Override is redefinition, but redefinition is not necessarilly override.
b) (following from a) redefinition is override only when the signature
(arguments) match and the function is virtual
Usando questa terminologia, che ripeto mi sembra più corretta, il titolo 
del thread sarebbe dovuto essere "Ri-definizione di metodo e argomenti 
default".

 
http://www.google.it/search?hl=it&rls=GGLD%2CGGLD%3A2004-37%2CGGLD%3Ait&q=override+sovrascrivere+&meta=
 
Che dicano quel che vogliono... semplicemente non sono d'accordo.
Sovrascrivere significa "scrivere sopra" e tale operazione, specialmente 
in informatica, è distruttiva.
Se la f originale fosse stata sovrascritta, non sarebbe più stato 
possibile chiamarla.
Forse non hai notato che in
b.A::f();
viene chiamata una f contenuta in /B/.
Questo significa che le due f coesistono ovvero non vi è stata 
sovrascrizione alcuna: B le contiene entrambe.
Se proprio vogliamo, non è la funzione ad essere sovrascritta, ma il suo 
identificatore.
Quindi non vedo perché parlare di sovrascrizione quando
a) il termine non significa "sovrascrivere" e
b) la funzione non viene in alcun modo sovrascritta.
Kiuhnm

 default".
Si tratta solo di mettersi d'accordo e di capirsi.
Quella che hai dato non è la definizione generale di "override".
Quando si studiano svariati linguaggi s'incomincia a capire che la 
terminologia non è assoluta. Ogni buon libro di matematica per es. 
contiene la definizione dei simboli utilizzati proprio perché 
differiscono lievemente a seconda che l'autore sia un logico, un fisico, 
ecc...
Per es., per alcuni, "a è minore di b" equivale ad "a <= b".
Altri indicano con N l'insieme {0, 1, 2, ...}, anziché l'insieme {1, 2, 
...}, ecc...
E' inutile perdere tempo a discutere su chi abbia ragione.
Kiuhnm

 derivata).
No. Non esiste "sovrascritto". Diventa nascosto e basta. E lo puoi 
rendere nuovamente visibile con una using declaration:
struct A {
   void foo(int);
};
struct B: public A {
   void foo(double);
};
struct C: public A {
   using A::foo;
   void foo(double);
};
B b;
b.foo(3);   // chiama B::foo passando 3.0
b.foo(3.3); // chiama B::foo passando 3.3
C c;
c.foo(3);   // chiama A::foo passando 3
c.foo(3.3); // chiama C::foo passando 3.3
In B B::foo è visibile mentre A::foo è nascosto. Mentre in C sia C::foo 
che A::foo sono visibili (e si applicano le normali regole di overloading).
Il fatto che si tratti di "hiding" e non di "ridefinizione" lo vedi 
anche chiaramente con i membri dati:
struct A {
   int bar;
};
struct B: public A {
   double bar;
};
nessuna ridefinizione: "B" ha due membri dato chiamati "bar". Uno, 
B::bar, è visibile. L'altro, A::bar, è nascosto.
Ma naturalmente:
struct C: public B {
   using A::bar;
};
"C" ha due membri dato chiamati "bar". Uno, A::bar, è visibile. L'altro, 
B::bar, nascosto.

 vero e proprio.
No. Si chiama "template instantiation". In questo codice esistono DUE 
distinte funzioni instanziate entrambe da uno stesso template. E non c'è 
alcun overriding (c'è l'hiding di A::f in B, ma ne A::f ne B::f vengono 
mai chiamate).

 Ad esempio si parla di "operator new overriding"
Nello standard no di certo. E chi ne parla commette un errore.

 default".
L'ideale sarebbe utilizzare i termini dello standard con lo stesso 
significato che hanno nello standard ;-)
Secondo lo standard non puoi ridefinire un metodo o un data member. Puoi 
ridefinire un nome.
In altre parole una classe derivata (ma vale in generale per ogni 
regione dichiarativa annidiata come il corpo di una funzione rispetto al 
suo namespace o come i namespace annidiati) può ridefinire un nome già 
in uso in una classe base. E' il meccanismo alla base dell' "hiding" 
(paragrafo 1 capitolo 3.3.7).

 terminologia non è assoluta. 
Parlando di C++ e usando termini che sono definiti all'interno dello 
standard del linguaggio, direi che si può (dovrebbe) ritenere corretta 
la definizione dello standard. E assoluta (in quanto qualificata dal 
contesto).
Che in un altro contesto "override" possa significare altro, resta vero.
E' un chiaro caso di "ridefinizione" di un *nome*. ;-P
Ma un nome può essere ridefinito solo in un altra regione dichiarativa o 
deve essere ridefinito identicamente, altrimenti è un errore (one 
definition rule). :-P

 definition rule). :-P
:)
Kiuhnm

 mai chiamate).
E' evidente che il codice per chiamarle è stato volutamente omesso.
Sta di fatto che l'effetto di definire B è quello di operare un 
"overriding".
Come disse una volta Maradona,
"Se mia nonna aveva i coglioni allora era mia nonno"!
Prima di essere programmatori di C++ siamo informatici.
Non posso cambiare terminologia ogni volta che cambio linguaggio.
Per es. molti standard chiamano "chiusura" la coppia (x = proc(...), EC) 
dove EC è l'intersezione tra il contesto lessicale dove è stata definita 
la procedura proc e l'insieme degli identificatori nominati in proc.
Dal mio punto di vista, questa è un'aberrazione. Preferisco continuare a 
dare a "chiusura" il significato algebrico (per es. usato nell'algebra 
delle strutture dati). Sono contento di constatare che gli autori di 
SICP la pensano allo stesso modo e infatti si discostano volutamente da 
definizioni usate dalla comunità lisp.
Quindi ti do ragione al 99% ;)
Kiuhnm

 "scavalca" se preferisci) una di base.
Sciocchezze. Nella terminologia del C++ standard il termine "override"
e' usato *esclusivamente* in riferimento alla reimplementazione di una
funzione membro virtuale in una classe derivata. Il fatto che tale
verbo abbia un significato piu' ampio nell'inglese comune e' del tutto
irrilevante.
Ciao,
Nicola