Maurizio Tomasi (maurizio.tomasi@unimi.it)
Martedì 21 ottobre 2025
La spiegazione dettagliata degli esercizi si trova qui: carminati-esercizi-05.html.
Come al solito, queste slides, che forniscono suggerimenti addizionali rispetto alla lezione di teoria, sono disponibili all’indirizzo ziotom78.github.io/tnds-tomasi-notebooks.
PosizioneParticella ed
ElettroneCampoVettoriale e
PuntoMaterialeAlcune funzioni utili disponibili in
<cmath>:
Per maggiori informazioni, eseguire man da
terminale
Consultate Wikipedia per comprendere
la logica di atan2.
[[nodiscard]] bool are_close(double calculated,
double expected,
double epsilon = 1e-7) {
return fabs(calculated - expected) < epsilon * fabs(expected);
}
void test_coordinates(void) {
Posizione p{1, 2, 3};
assert(are_close(p.getX(), 1.0));
assert(are_close(p.getY(), 2.0);
assert(are_close(p.getZ(), 3.0);
assert(are_close(p.getR(), 3.7416573867739));
assert(are_close(p.getPhi(), 1.1071487177941);
assert(are_close(p.getTheta(), 0.64052231267943);
assert(are_close(p.getRho(), 2.2360679774998);
println(cerr, "The coordinates work correctly! 🥳");
}L’esempio usa new per creare puntatori:
Particella a{1., 1.6e-19};
Elettrone *e{new Elettrone{}};
CorpoCeleste *c{new CorpoCeleste{"Terra", 6.0e24, 6.4e6}};Questo è utile per lo scopo dell’esercizio (comprendere come funziona l’ereditarietà).
In un vero programma l’uso di new e
delete espliciti andrebbe però limitato il più possibile (e
in questi pochissimi casi, andrebbe comunque usato solamente in
costruttori/distruttori di classi, mai nel main).
Estratto dall’articolo C++ is the next C++, che propone una nuova «modalità» di compilazione del C++ in cui disabilitare (quasi) del tutto i puntatori.
void test_coulomb_law(void) {
// 0.5 µC charge with no mass (irrelevant for the electric field)
PuntoMateriale particella{0.0, 5e-7, 5, 3, -2};
Posizione p{-2, 4, 1};
CampoVettoriale V{particella.CampoElettrico(p)};
assert(are_close(V.getFx(), -69.41150052142065));
assert(are_close(V.getFy(), 9.915928645917235));
assert(are_close(V.getFz(), 29.747785937751708));
println(cerr, "Coulomb's law works correctly! 🥳");
}
void test_newton_law(void) {
// 10⁹ tonnes, without charge (irrelevant for the gravitational field)
PuntoMateriale particella{1e12, 0, 5, 3, -2};
Posizione p{-2, 4, 1};
CampoVettoriale V{particella.CampoGravitazionale(p)};
assert(are_close(V.getFx(), -1.0302576701177));
assert(are_close(V.getFy(), 0.14717966715968));
assert(are_close(V.getFz(), 0.44153900147903));
println(cerr, "Newton's law works correctly! 🥳");
}Per inizializzare i membri di una classe in C++ esistono tre possibilità:
Uno dei metodi è diverso dagli altri due!
Costruiamo una classe DaylightPeriod che contiene al
suo interno tre variabili dello stesso tipo Time che sono
inizializzate in modo diverso:
Per capire cosa succede, definiamo Time in modo che
stampi a video un messaggio ogni volta che viene invocato un suo
metodo.
Compiliamo ora questo programma ed eseguiamolo:
L’output è il seguente:
Call to Time constructor with time "12:00"
Call to Time constructor with time "7:00"
Time() called with no arguments
Call to Time constructor with time "21:00"
Call to Time::operator=Ricordiamo come abbiamo definito la classe
DaylightPeriod:
L’output rivela che sunset ha richiesto più lavoro
delle altre due!
Call to Time constructor with time "12:00"
Call to Time constructor with time "7:00"
Time() called with no arguments
Call to Time constructor with time "21:00"
Call to Time::operator=Se il valore iniziale non cambia mai, fate come
noon{"12:00"}:
Se il valore iniziale è un parametro o dovete chiamare il
costruttore della classe base, fate come
: dawn{"7:00"}:
In ogni altro caso, usate il corpo del costruttore
Se nella dichiarazione di una classe si scrive
= default dopo il costruttore, si chiede al C++ di
implementarlo nel modo migliore possibile:
Un costruttore definito in questo modo garantisce che
m_x, m_y e m_z siano
inizializzate ai valori 1.0, 2.0, 3.0 e in più abilita
altre proprietà avanzate se si usano i template o i
constexpr
default e deleteSi può usare = default anche con i copy constructor,
i move constructor, e i distruttori, e il significato è lo
stesso
Si può anche specificare = delete, che dice al C++
di non definire un costruttore di default, o un copy
constructor, o un move constructor:
Dopo le fatiche della scorsa lezione, mi sono documentato su alcune alternative a Visual Studio Code che non riempiano a tradimento le vostre home directory
Ho scoperto che Geany è installato sulle macchine del laboratorio, ed è una valida opzione a VSCode
Per chi usa il proprio portatile non c’è bisogno di cambiare, ma chi invece usa il computer del laboratorio dovrebbe prenderlo in considerazione
Per permettere a Geany di usare il C++23, aprite un terminale ed eseguite questa riga:
/home/comune/labTNDS_programmi/setup-geanyOra potete far partire Geany ed usarlo per compilare codice ed eseguirlo
Con Shift+F9 eseguite make
Con F5 eseguite make esegui, a patto
che abbiate definito il target esegui nel vostro
Makefile! (Questo funziona solo se state editando un file
C++; se è aperto il Makefile, il tasto non
funziona).
Scegliendo da menu “Build/Auto-format” e premendo Ctrl+R, viene riformattato il vostro codice C++
Potete attivare molti plug-in interessanti da “Tools / Plugin manager”; io vi consiglio Auto-close, Debugger e File Browser.
Da quest’anno ho reso disponibile il programma NND, un debugger semplice ma adatto agli scopi di queste esercitazioni
Potete installarlo nella vostra home con questo comando:
/home/comune/labTNDS_programmi/install-nddLe istruzioni complete sono disponibili in una pagina dedicata.
Potete scaricarlo da qui per i vostri portatili; purtroppo però funziona solo su Linux…