In questo scenario, si pompa un altro tempo dopo che l'utente ha premuto "0". Supponendo che ciò non sia desiderato, si dispone di ciò che è noto come "errore di errore singolo". È possibile risolvere questo (ed eliminare la variabile temporanea) riorganizzando la funzione come segue:
void GasPump::dispense()
{
while (true) {
cout << "Press any key, or enter to dispense.\n"
<< "Or press 0 to stop: \n";
if (cin.get() == '0')
break;
gasDispensed = gasDispensed + gasDispensedPerCycle;
charges = costPerGallon*gasDispensed;
displayGasNCharges();
}
}
Per evitare di utilizzare un'istruzione break, è possibile utilizzare la seguente costruzione:
bool GasPump::shouldDispenseGas()
{
cout << "Press any key, or enter to dispense.\n"
<< "Or press 0 to stop: \n";
return (cin.get() != '0');
}
void GasPump::dispense()
{
while (shouldDispenseGas()) {
gasDispensed = gasDispensed + gasDispensedPerCycle;
charges = costPerGallon*gasDispensed;
displayGasNCharges();
}
}
EDIT (2011 Settembre 27): @TonyK Solo perché una lingua fornisce una funzionalità non significa che si dovrebbe usarla. L'istruzione goto
è un classico esempio di questo.
Concesso, con un ciclo così semplice, non c'è davvero alcuna differenza tra l'utilizzo di una funzione e l'interruzione. Entrambi sono chiari. Tuttavia, quando le funzionalità extra vengono aggiunte un mese (o anni) più tardi, insieme a condizioni aggiuntive per rompere il loop, è molto facile trovare dichiarazioni if
con una logica complessa all'interno di un ciclo così grande, si ha un duro tempo che trova il suo inizio, molto meno i punti di uscita. Uno dei modi per combattere questo tipo di codice è quello di scrivere funzioni brevi, semplici e focalizzate che siano ben definite. Se lo fai, il codice si documenta da solo. Confronta
while (true)
contro
while (shouldDispenseGas())
Allo stesso modo, confronta al STL for_each
algoritmo. Certo, std::for_each(v.begin(), v.end(), &foo);
è un po 'più corto di for (int i = 0; i < v.size(); ++i) { ...body of foo()... }
. Ma il vero vantaggio è che è più facile vedere quale sia l'intento. Nello for_each
si vede subito che si farà qualcosa una volta sola, e solo una volta, a ciascun elemento. Nel ciclo for, non hai idea. Il contatore di loop i
può essere modificato nel ciclo. A break
potrebbe essere nascosto anche all'interno. Escludendo questa istruzione break
e incorporando la logica in shouldDispenseGas
, si capisce immediatamente le condizioni in base alle quali il ciclo continuerà e terminerà.
Ooh! Non mi rendevo conto che quando si utilizzava un numero decimale come carattere si doveva mettere le virgolette intorno, buono a sapersi, grazie mille! –
@ blakejc70 Poiché stop è un char e con il metodo C++ che esegue l'overloading, la chiamata a cin.get viene instradata a una logica di gestione dell'input che restituirà un codice di carattere. Quindi stop == '0' == 48 (andando per ipotesi di set di caratteri ASCII). – David