-
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.
- Esercizio 5.0: Creazione della classe
Posizione
- Esercizio 5.1: Creazione della classe
Particella
edElettrone
- Esercizio 5.2: Creazione delle classi
CampoVettoriale
ePuntoMateriale
- Esercizio 5.3: Calcolo del campo elettrico generato da un dipolo (da consegnare)
- Esercizio 5.4: Campo di multipolo (approfondimento)
- Esercizio 5.5: Gravità dallo spazio (approfondimento)
-
Alcune funzioni utili disponibili in
<cmath>
:double std::sin(double x); double std::cos(double x); double std::tan(double x); double std::atan(double x); double std::atan2(double y, double x);
-
Per maggiori informazioni, eseguire
man
da terminale$ man atan2
-
Consultate Wikipedia per comprendere la logica di
atan2
.
bool are_close(double calculated, double expected, double epsilon = 1e-7) {
return fabs(calculated - expected) < epsilon;
}
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);
cerr << "The coordinates work correctly! 🥳\n";
}
-
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
edelete
espliciti andrebbe però limitato il più possibile (e in questi pochissimi casi, andrebbe comunque usato solamente in costruttori/distruttori di classi, mai nelmain
).
{width=40%}
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 particella1{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));
cerr << "Coulomb's law works correctly! 🥳\n";
}
void test_newton_law(void) {
// 10⁹ tonnes, without charge (irrelevant for the gravitational field)
PuntoMateriale particella1{1e12, 0, 5, 3, -2};
Posizione p{-2, 4, 1};
CampoVettoriale V{particella.CampoElettrico(p)};
assert(are_close(V.getFx(), -1.0302576701177));
assert(are_close(V.getFy(), 0.14717966715968));
assert(are_close(V.getFz(), 0.44153900147903));
cerr << "Newton's law works correctly! 🥳\n";
}
Per inizializzare i membri di una classe in C++ esistono due possibilità:
class Prova {
public:
Prova();
private:
int a;
double b;
};
Prova::Prova() : a{1} { // Initializer: use ":" *before* the {
b = 5.0; // Old boring assignment
}
-
I due metodi non sono equivalenti!
-
Costruiamo una classe
DaylightPeriod
che contiene al suo interno due variabili dello stesso tipoTime
, ma inizializzate in modo diverso:class DaylightPeriod { public: // Pass two strings as names to distinguish the two objects DaylightPeriod() : dawn{"7:00"} { sunset = Time("21:00"); } private: Time dawn, sunset; };
Per capire cosa succede, definiamo Time
in modo che stampi a video un messaggio ogni volta che viene invocato un suo metodo.
class Time {
public:
Time() { std::cout << "Time() called with no arguments\n"; }
Time(const char *time) {
std::cout << std::format("Call to Time constructor with time \"{}\"\n", time);
}
void operator=(const Time &) {
std::cout << "Call to Time::operator=\n";
}
};
Se ora creiamo nel main
una variabile DaylightPeriod
, vedremo cosa
accade nel costruttore:
int main(void) {
DaylightPeriod c{};
return 0;
}
-
L'output del programma è il seguente:
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
, e in particolare il costruttore:class DaylightPeriod { public: DaylightPeriod() : dawn{"7:00"} { sunset = Time("21:00"); } private: Time dawn, sunset; };
-
Si dovrebbe evitare di inizializzare gli oggetti nel corpo del costruttore, perché il C++ richiede che tutte le variabili membro siano inizializzate prima che il costruttore di una classe sia eseguito.
-
Di conseguenza, se si usano i «vecchi» assegnamenti gli oggetti con costruttore vengono inizializzati due volte.
-
Se avete scelta, l'inizializzazione con i due punti (
:
) è sempre da preferire:class DaylightPeriod { public: DaylightPeriod() : dawn{"7:00"}, sunset{"21:00"} { } // That's the way! // ... };
title: Laboratorio di TNDS -- Lezione 5 author: Maurizio Tomasi date: "Martedì 22 Ottobre 2024" theme: white progress: true slideNumber: true background-image: ./media/background.png history: true width: 1440 height: 810 css:
- ./css/custom.css
- ./css/asciinema-player.css ...