2009-05-16 8 views
29

Sto facendo gli esercizi nel nuovo libro di Stroustrup "Programming Principles and Practice Using C++" e mi chiedevo se qualcuno su SO li ha fatti ed è disposto a condividere le conoscenze? In particolare sulla calcolatrice sviluppata nel Cap 6 e 7. Ad esempio le domande sull'aggiunta del! operator e sqrt(), pow() ecc. Ho fatto questi, ma non so se la soluzione che ho è il modo "buono" di fare le cose, e non ci sono soluzioni pubblicate sul sito web di Bjarne. Mi piacerebbe sapere se sto andando nella giusta direzione. Forse possiamo fare un wiki per gli esercizi?Aggiunta del! operatore e sqrt(), pow() ecc. per un'applicazione di esempio di calcolatore

Fondamentalmente ho un parser di token. Legge un carattere alla volta da cin. Ha lo scopo di rendere le espressioni come 5 * 3 + 1 e funziona benissimo per questo. Uno degli esercizi è aggiungere una funzione sqrt(). Così ho modificato il codice tokenising per rilevare "sqrt (" e quindi restituire un oggetto Token che rappresenta sqrt. In questo caso uso i caratteri "." È così che gli altri lo farebbero? "E se dovessi implementare sin()? l'istruzione case otterrebbe disordinato.

char ch; 
cin >> ch; // note that >> skips whitespace (space, newline, tab, etc.) 

switch (ch) { 
    case ';': // for "print" 
    case 'q': // for "quit" 
    case '(': 
    case ')': 
    case '+': 
    case '-': 
    case '*': 
    case '/': 
    case '!': 
     return Token(ch);  // let each character represent itself 
    case '.': 
    case '0': case '1': case '2': case '3': case '4': 
    case '5': case '6': case '7': case '8': case '9': 
     {  
      cin.putback(ch);   // put digit back into the input stream 
      double val; 
      cin >> val;    // read a floating-point number 
      return Token('8',val); // let '8' represent "a number" 
     } 
    case 's': 
     { 
      char q, r, t, br; 
      cin >> q >> r >> t >> br; 
      if (q == 'q' && r == 'r' && t == 't' && br == '(') { 
       cin.putback('('); // put back the bracket 
       return Token('s'); // let 's' represent sqrt 
      } 

     } 

    default: 
     error("Bad token"); 
} 
+0

Inserisci qui il tuo codice e molte persone saranno felici di dirti cosa può essere migliorato. Questo sito è tutto il wiki di cui hai bisogno. :) – jalf

+0

Ok, lo farò presto! – PowerApp101

+0

Non ho visto l'esercizio, ma ciò che sembra strano è che si tenta di fare il doppio di ogni cifra e punto decimale che si incontra. – jbasko

risposta

210
  • ci sono alcune soluzioni pubblicate su Stroustrup - Programming e più volontà essere comin g nel tempo.

  • Prova a risolvere gli esercizi solo con le funzionalità linguistiche e le funzionalità di libreria presentate finora nel libro: gli utenti principianti non possono fare altro. Quindi torna più tardi per vedere come una soluzione può essere migliorata.

+2

Sì, stavo un po 'tradendo con la mappa ... non appare fino ai prossimi capitoli. A proposito, mi sto davvero godendo il libro. Penso che la calcolatrice potrebbe effettivamente essere utile nel mondo reale, che non è qualcosa che puoi dire dei campioni presentati nella maggior parte dei libri introduttivi. – PowerApp101

0

vorrei spostare il rilevamento 'sqrt' in un altro metodo per il rilevamento delle funzioni. in sostanza, mi permetterebbe di eliminare il rilevamento dei 's' e aggiungere qualcosa all'interno del caso di default che avrebbe letto il stringa fino a un '('.

Se no '(' viene rilevato, quindi errore.

Se si legge con successo una stringa, passare che a un nome di funzione pa rser che usa la stringa comparata per generare un token che rappresenta una chiamata a sqrt o sin o qualsiasi altra funzione tu voglia. Il metodo che controlla i nomi delle funzioni può anche essere errato se legge una stringa che non riconosce.

+0

Ok, cercherò di implementare questo Sarebbe bello separare le funzioni. – PowerApp101

10

ho pensato una mappa di stringhe di funzionare puntatori potrebbe essere un modo conciso per rappresentare le cose come sqrt, sin, cos etc che prendono un singolo doppio e restituire un doppio:

map<std::string, double (*)(double)> funcs; 
funcs["sqrt"] = &sqrt; 
funcs["sin"] = &sin; 
funcs["cos"] = &cos; 

poi, quando il rileva parser una stringa corretta (str) può chiamare la funzione con un argomento (arg) in questo modo:

double result = funcs[str](arg); 

con questo metodo una singola chiamata può gestire tutti i casi di funzioni (di questo tipo).

In realtà non sono sicuro che sia la sintassi corretta, qualcuno può confermare?

Questo sembra un metodo utilizzabile?

+7

Potrebbe, ma Bjarne Stroustrup ha risposto alle tue domande zione. Inchinarsi. –

4

E 'più facile lavorare con le classi derivate e le funzioni virtuali: ciascuna classe specializzata leggere il suo ingresso ...

class base{public: 
virtual double calc()=0; 
}; 
class get_sqrt:public base{ 
int useless; 
public: 
virtual double calc(){cin>>number;return sqrt(number);} 
}get_sqrt; 

ora organizziamo questi in una mappa, useremo soltanto i loro puntatori:

map<string,base*> func; 
func["sqrt"]=&get_sqrt; 

c'è anche un metodo specializzato che esamina solo il carattere successivo: peek();

char c=cin.peek(); 

è possibile eliminare l'interruttore utilizzando 1 se e mettendo! + - ...in func; (Dovrebbero operare su left_param per semplicità

if (c>='0'&&c<='9') cin>>right_param; //get a number, you don't have to put the character back as it hasn't been removed 
else{string s; cin>>s;right_param=func[s]->calc();} 

Quindi, in pratica una sorta di puntatori a funzione, ma senza la sintassi disordinato e in strega è possibile memorizzare i dati tra i calcoli

EDIT: ho pensato al problema di spazio bianco;. può essere aggiunto prima di iniziare a calcolare, penso anche che ci potrebbe essere un modo per impostare diversi separatori, come i numeri, ma non so come fare.

+0

Bello. Sapevo che ci sarebbe stata una soluzione OOP da qualche parte! Ma ... il cin >> s non funzionerebbe perché l'espressione non poteva contenere spazi bianchi, cioè 5 + sqrt (144)/2. Quindi ho ancora bisogno di leggere un carattere alla volta per controllare il nome della funzione come sqrt, penso. – PowerApp101

+0

Penso che dovrebbe essere sbalorditivo, non di punta! Mi chiedo perché Stroustrup non abbia usato questo metodo, sembra più logico di get() e putback(). – PowerApp101

+7

Mi sono astenuto dall'usare peek() per evitare di introdurre questa nuova struttura in anticipo e (soprattutto) perché "stream with putback()" è un'idea molto generica che può essere usata in molti posti - peek() coinvolge qualcun altro un po 'di buffering per te. Inoltre, pensa agli spazi bianchi e alla gestione degli errori - cosa succede se non c'è un prossimo personaggio da sbirciare? Vedo peek() più come un "trucco intelligente" che come tecnica generale. –

Problemi correlati