Torna indietro   Hardware Upgrade Forum > Software > Programmazione

AWS annuncia European Sovereign Cloud, il cloud sovrano per convincere l'Europa
AWS annuncia European Sovereign Cloud, il cloud sovrano per convincere l'Europa
AWS è il principale operatore di servizi cloud al mondo e da tempo parla delle misure che mette in atto per garantire una maggiore sovranità alle organizzazioni europee. L'azienda ha ora lanciato AWS European Sovereign Cloud, una soluzione specificamente progettata per essere separata e distinta dal cloud "normale" e offrire maggiori tutele e garanzie di sovranità
Redmi Note 15 Pro+ 5G: autonomia monstre e display luminoso, ma il prezzo è alto
Redmi Note 15 Pro+ 5G: autonomia monstre e display luminoso, ma il prezzo è alto
Xiaomi ha portato sul mercato internazionale la nuova serie Redmi Note, che rappresenta spesso una delle migliori scelte per chi non vuole spendere molto. Il modello 15 Pro+ punta tutto su una batteria capiente e su un ampio display luminoso, sacrificando qualcosa in termini di potenza bruta e velocità di ricarica
HONOR Magic 8 Pro: ecco il primo TOP del 2026! La recensione
HONOR Magic 8 Pro: ecco il primo TOP del 2026! La recensione
HONOR ha finalmente lanciato il suo nuovo flagship: Magic 8 Pro. Lo abbiamo provato a fondo in queste settimane e ve lo raccontiamo nella nostra recensione completa. HONOR rimane fedele alle linee della versione precedente, aggiungendo però un nuovo tasto dedicato all'AI. Ma è al suo interno che c'è la vera rivoluzione grazie al nuovo Snapdragon 8 Elite Gen 5 e alla nuova MagicOS 10
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 26-10-2001, 17:26   #1
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
C++: Questa proprio non la sapevo

Guardate questo codice:

#include <iostream.h>
class C1 {
virtual void print () { cout << "print() di C1\n"; }
public:
C1 () { print(); }
void do_print () { print (); }
};

class C2: public C1 {
void print () { cout << "print() di C2\n"; }
};

int main() {
C2 C;
C.do_print();
return 0;
}

L'output del programma è:
print() di C1
print() di C2
ed è uguale sia sul g++ 2.91, g++ 2.96 che sul visual c.
Succo: nei costruttori di classe le funzioni virtuali a quanto pare non sono usate come tali - qualcuno ne sa qualcosa di più a riguardo?
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 26-10-2001, 18:11   #2
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Sinceramente non mi ricordo come funziona l'ereditariatà sul costruttore di default...in ogni caso sembra che tu abbia ereditato anche quello...
Infatti con "C2 C;" richiami il costruttore di default di C2 erediatato da C1 e poi con "do_print()" che è ereditata da C1 richiami la print() di C2 come è sicuramente giusto (visto che l'stanza è di tipo C2)...

Comunque funziona allo stesso modo anche in VC++...
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 26-10-2001, 20:23   #3
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
No, non è così, il costruttore di C1 viene chiamato prima di quello di default di C2, è normale che sia così. Il problema è che a quanto sembra, C viene inizialmente costruito come C1, poi come C2. Solo questo può spiegare il fatto che, se il costruttore chiama una funzione virtuale, non viene chiamata quella effettiva della classe di appartenenza.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 03:28   #4
Black imp
Senior Member
 
Iscritto dal: Nov 2000
Città: MILANO
Messaggi: 2662
.
Black imp è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 03:44   #5
Black imp
Senior Member
 
Iscritto dal: Nov 2000
Città: MILANO
Messaggi: 2662
la chiamata a print è fatta in una funzione di C1 e chiama un'altra funzione dello scope di C1. Quindi mi sembra normale che NON possa vedere un elemento funzione di C2.
facciamo un altro esempio che scrivo adesso sperando di non confonderti le idee:

class A {

public:
A();
virtual print() {printf("classe A\n"};
};

class Bublic A {

public:
print() { printf("classe B\n"); };

}


int main() {

A a;
a.print();
B b;
b.print();

}

deve stamparti "classe A" e poi "classe B" e tutto funziona correttamente secondo le regole. Nel tuo esempio la funzione che ridefinisci innanzi tutto è privata e non può essere ridefinita perchè la classe derivata può accedere solo ai membri pubblc della super classe. In secondo luogo tu chiami esplicitamente una funzione della superclasse - NON della derivata - e che perciò non può " vedere " nello scope della derivata - ci mancherebbe - e chiama corettamente la funzione print() del SUO scope. Occhio perchè questo esempio è molto incasinato. Non si usa in questo modo il polimorfismo. Inoltre usa sempre i puntatori quando hai a che fare con il polimorfismo: altrimenti non serve a nulla.

Ad es. tu sai che devi tenere un elenco di oggetti Sensor in un tuo programma ma non sai ancora se questi oggetti in particolare saranno dei TouchSensor o dei LightSensor ecc. Allora tieni un vettore di puntatori a Sensor e per ognuno a run time allocherai la giusta classe derivata. In questo modo, chiamando i metodi virtuali - stiamo parlando di metodi virtuali NON puri ovviamente - della classe Sensor, verranno in realtà invocati i corrispettivi metodi della derivata:


Sensor* lista[10];

lista[0]= new LightSensor();

ecc.
Black imp è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 10:36   #6
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
la chiamata a print è fatta in una funzione di C1 e chiama un'altra funzione dello scope di C1. Quindi mi sembra normale che NON possa vedere un elemento funzione di C2.
No, questo non è corretto, in quanto print è dichiarata virtuale, e quindi soggetta a polimorfismo in caso di ereditarierà. Infatti, come puoi vedere, do_print() è una funzione di C1 ma è in grado di invocare la print() polimorfa corretta, ovvero quella di C2 nell'esempio. A quanto pare solo i costruttori fanno eccezione a questa regola, ma non ne capisco il motivo (sicuramente ce n'è uno)
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 14:01   #7
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Non capisco qual è il problema...la print di C1 è virtuale...quindi, visto che è definita anche la print di C2 nella vtable della classe è presente il puntatore alla funzione print di C2...
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 14:39   #8
/\/\@®¢Ø
Bannato
 
L'Avatar di /\/\@®¢Ø
 
Iscritto dal: Jul 2000
Città: Malo (VI)
Messaggi: 1000
Anche a me e' accaduto un problema simile,
solo che la funzione nella classe base non era definita, e quindi il programma crashava con un "Pure virtual method called" o qualcosa di simile ( provare per credere ).
Probabilmente ogni costruttore provvede solamente ad aggiungere ( ovvero sovrascrivere ) nella virtual table i metodi ridefiniti. QUando sei nel costruttore della classe base di conseguenza, non hai nessun metodo ridefinito.
Perche' non hanno deciso di scrivere subito la virtual table completa ?
Secondo me l'hanno fatto per poter riutilizzare i costruttori delle classi basi senza doverli spezzare in piu' parti, a vantaggio dell'efficienza.
( Anche se quest'ultima cosa e' solo una mia ipotesi ).
/\/\@®¢Ø è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 14:41   #9
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
Non capisco qual è il problema...la print di C1 è virtuale...quindi, visto che è definita anche la print di C2 nella vtable della classe è presente il puntatore alla funzione print di C2...
Appunto: tutte le funzioni di C1 invoncano la funzione "giusta" di C2; tutte tranne costruttore e distruttore di C1...è il "perchè" che mi sfugge. Questo vuol dire inoltre che non puoi definire una classe astratta nella quale una funzione virtuale pura (magari da implementare fisicamente in una classe che eredita) viene invocata dal costruttore.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 14:44   #10
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
Originariamente inviato da /\/\@®¢Ø
QUando sei nel costruttore della classe base di conseguenza, non hai nessun metodo ridefinito.
Perche' non hanno deciso di scrivere subito la virtual table completa ?
Secondo me l'hanno fatto per poter riutilizzare i costruttori delle classi basi senza doverli spezzare in piu' parti, a vantaggio dell'efficienza.
( Anche se quest'ultima cosa e' solo una mia ipotesi ).
Non credo che si tratti di efficienza, in quanto aggiornare la vtable prima o dopo la chiamata al costruttore non cambia la velocità. Credo che tutto dipenda da qualche specifica del c++ della quale però mi sfugge la motivazione...
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 15:00   #11
/\/\@®¢Ø
Bannato
 
L'Avatar di /\/\@®¢Ø
 
Iscritto dal: Jul 2000
Città: Malo (VI)
Messaggi: 1000
Cerco di spiegarmi meglio:

La 'costruzione' di un oggetto richiede vari cose giusto ( 'aggiustamento' )della vtable esecuzione del costruttore definito dall'utente e cosi' via ).
Ora se io volessi avere da subito la virtual table "esatta", dovrei riuscire a effettuare solo parte di queste operazioni, in particolare escludere la scrittura della vtable da parte dei costruttori derivati, ( perche' altrimenti la stessa tornerebbe 'carente' ). E' probabile che questo sia di difficile esecuzione: se pensi che potrei aver derivato un oggetto che mi arriva da una libreria esterna, questo vuol dire che ogni libreria dovrebbe esportare una certa quantita' di funzioni ( o comunque di informazioni ) da chiamare in caso di derivazione.
/\/\@®¢Ø è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 15:32   #12
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
mmm questo mi sembra già più convincente, anche se continuo ad avere dei dubbi sul fatto che modi alternativi siano impossibili da gestire
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 19:15   #13
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Posso provare a dare una spiegazione...un po' a occhio...

Implementando il costruttore di default per C2 viene lo stesso richiamato il costruttore di default di C1...
Quindi al momento della chiamata del costruttore di C1 si tratta di costruire un oggetto di tipo C1...la cui vtable verrà poi sovrascritta dalla creazione dell'oggetto C2 che viene derivato da C1 di cui eredita la parte pubblica...

Quindi secondo me il compilatore opera in questo modo...

Crea un'istanza di C1 e ne chiama il costruttore (a questo punto l'oggetto è ancora di tipo C1...ed è per questo che viene chiamata la print di C1)...l'istanza di C2 eredita i membri e le funzioni pubbliche di C1...viene modificata la vtable (viene sovrascritta l'entry di print())...poi successivamente viene chiamato il costruttore di C2...

Modificando il codice in questo modo si vede che quello che avviene sembra essere questo...

#include <iostream.h>

class C1 {
virtual void print () { cout << "print() di C1\n"; }
public:
C1 () { print(); }

void do_print () { print (); }
};

class C2: public C1 {
void print () { cout << "print() di C2\n"; }
public :
C2 () {print();};
};

int main() {
C2 C;
C.do_print();

return 0;
}
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 19:31   #14
Black imp
Senior Member
 
Iscritto dal: Nov 2000
Città: MILANO
Messaggi: 2662
MA RAGAZZI!!! ho capito adesso la domanda. MA NON SCHERZIAMO!! quando ereditate una classe VIENE SEMPRE CHIAMATO IL COSTRUTTORE DELLA SUPERCLASSE se no non funzionerebbe più niente. E che senso avrebbe?

per IL_sensine: non sono sicuro di come funzioni in questo caso. ripasserò un po'. comunque se chiamate q.sa che sta solo nella superclasse questo NON può vedere la parte 'aggiunta ' ereditando.
Black imp è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 20:10   #15
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
MA RAGAZZI!!! ho capito adesso la domanda. MA NON SCHERZIAMO!! quando ereditate una classe VIENE SEMPRE CHIAMATO IL COSTRUTTORE DELLA SUPERCLASSE se no non funzionerebbe più niente. E che senso avrebbe?
Questo è ovvio, non è in discussione. C1::C1() viene sempre chiamato.

Quote:
per IL_sensine
(ilsensine svp)

Quote:
se chiamate q.sa che sta solo nella superclasse questo NON può vedere la parte 'aggiunta ' ereditando.
Qui non stiamo parlando di parti aggiunte, ma di parti polimorfe. Come vedi, do_print() sta solo in C1 ma chiama comunque correttamente la funzione (polimorfa, in quanto virtuale in C1 e ridefinita in C2) implementata in C2.

Il problema (che cionci e /\/\@®¢Ø) hanno intuito) a quanto pare è che la vtable viene costruita mano mano che vengono chiamati i costruttori delle classi, e non _prima_ come mi sarei aspettato. Tutto qui.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 20:15   #16
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Certo...
Al momento della chiamata del costruttore di C1 l'istanza è a tutti gli effetti della classe C1...poi successivamente viene modificata la vtable al momento dell'allocazione di C2...
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-10-2001, 20:20   #17
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
poi successivamente viene modificata la vtable al momento dell'allocazione di C2...
a questo punto direi: "al momento della trasformazione in C2". In effetti quello che accade sembra essere proprio questo, anche se il termine è improprio.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 28-10-2001, 02:50   #18
Black imp
Senior Member
 
Iscritto dal: Nov 2000
Città: MILANO
Messaggi: 2662
allora non avevo capito. forse perchè questo mi sembrava più ovvio mentre in realtà mi sono accorto che non mi ricordo bene altri aspetti a dire il vero
Black imp è offline   Rispondi citando il messaggio o parte di esso
Old 28-10-2001, 02:59   #19
Black imp
Senior Member
 
Iscritto dal: Nov 2000
Città: MILANO
Messaggi: 2662
AAAAAHHHH adesso ho capito ancora meglio! in sostanza il problema è che secondo voi non doveva invocare la print di C1 durante l'invocazione al costruttore, perchè questa è già stata ridefinita. Mhhh beh quando viene chiamato il costruttore della super classe - vale anche per una catena di ereditarietà - l'oggetto modifica tipo man mano: se C eredita da B che eredita da A, quando si crea un oggetto C, prima viene costruito un oggetto A poi esteso a B poi esteso a C. quindi mi sembra coerente che durante l'esecuzione del costruttore di C1 chiami ancora la print di C1. Non so se questo in effetti sia un limite anzi. Direi che se si cercasse di fare veramente una cosa come nell'esempio con quell'intento, sarebbe sbagliata la scelta di ereditare C2 da C1 - non sto criticando chi lo ha scritto - non vi pare?
Black imp è offline   Rispondi citando il messaggio o parte di esso
Old 28-10-2001, 10:02   #20
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
quindi mi sembra coerente che durante l'esecuzione del costruttore di C1 chiami ancora la print di C1.
Assodato che la costruzione di una classe derivata avviene per gradi, è coerente.
Quote:
Non so se questo in effetti sia un limite anzi.
Forse è un limite. Supponi a titolo di esempio di definire una classe generica Numero, il cui costruttore chiami una funzione virtuale che alloca la memoria necessaria a contenere il numero. Poichè ancora non è stato definito di che numero si tratti e di quanta memoria sia necessaria per contenerlo, tale funzione può essere definita virtuale pura (ovviamente, da ciò che abbiamo visto, non è possibile). Poi ogni derivazione di Numero (ad es. Intero, Complesso ecc.) potrebbe ridefinire una propria istanza di tale funzione per allocare la memoria necessaria. Se la vtable fosse stata aggiornata prima della chiamata alla catena di costruttori, una cosa del genere avrebbe funzionato. Prendiamo atto che però non è così.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


AWS annuncia European Sovereign Cloud, il cloud sovrano per convincere l'Europa AWS annuncia European Sovereign Cloud, il cloud ...
Redmi Note 15 Pro+ 5G: autonomia monstre e display luminoso, ma il prezzo è alto Redmi Note 15 Pro+ 5G: autonomia monstre e displ...
HONOR Magic 8 Pro: ecco il primo TOP del 2026! La recensione HONOR Magic 8 Pro: ecco il primo TOP del 2026! L...
Insta360 Link 2 Pro e 2C Pro: le webcam 4K che ti seguono, anche con gimbal integrata Insta360 Link 2 Pro e 2C Pro: le webcam 4K che t...
Motorola edge 70: lo smartphone ultrasottile che non rinuncia a batteria e concretezza Motorola edge 70: lo smartphone ultrasottile che...
iPhone Air 2 non avrà il Face ID ...
OnePlus 15R con Snapdragon 8 Gen 5 verso...
Il futuro Samsung Galaxy A57 non ha (qua...
Motorola prepara un altro best buy per l...
OnePlus già lavora al suo prossim...
PS5 Slim con SSD da 1 TB e Blu-ray scend...
La crisi delle memorie non si ferma: rin...
REDMAGIC 11 Air è ufficiale: tant...
Le dimensioni contano? C'è un TV ...
Vast prosegue la costruzione della stazi...
Chiarito cosa è successo al satel...
Il TAR annulla Bologna Città 30. ...
Laptop con chip NVIDIA da marzo? Emergon...
Costruito in casa, più veloce di ...
Il nuovo Galaxy Book 6 Pro costa il 25% ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 09:23.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v