--- language: c++ filename: learncpp.cpp contributors: - ["Steven Basart", "http://github.com/xksteven"] - ["Matt Kline", "https://github.com/mrkline"] translators: - ["Robert Margelli", "http://github.com/sinkswim/"] lang: it-it --- Il C++ e' un linguaggio di programmazione il quale, [secondo il suo inventore Bjarne Stroustrup](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote), e' stato progettato per - essere un "miglior C" - supportare l'astrazione dei dati - supportare la programmazione orientata agli oggetti - supportare la programmazione generica Nonostante la sintassi possa risultare piu' difficile o complessa di linguaggi piu' recenti, e' usato in maniera vasta poiche' viene compilato in istruzioni macchina che possono essere eseguite direttamente dal processore ed offre un controllo stretto sull'hardware (come il linguaggio C) ed allo stesso tempo offre caratteristiche ad alto livello come i generici, le eccezioni, e le classi. Questa combinazione di velocita' e funzionalita' rende il C++ uno dei piu' utilizzati linguaggi di programmazione. ```c++ ////////////////// // Confronto con il C ////////////////// // Il C++ e' _quasi_ un superset del C e con esso condivide la sintassi di base per // la dichiarazione di variabili, tipi primitivi, e funzioni. // Proprio come nel C, l'inizio del programma e' una funzione chiamata // main con un intero come tipo di ritorno, // nonostante void main() sia anch'essa accettata dalla maggior parte dei compilatori(gcc, clang, ecc...) // Questo valore serve come stato d'uscita del programma. // Vedi http://it.wikipedia.org/wiki/Valore_di_uscita per maggiori informazioni. int main(int argc, char** argv) { // Gli argomenti a linea di comando sono passati tramite argc e argv cosi' come // avviene in C. // argc indica il numero di argomenti, // e argv e' un array in stile-C di stringhe (char*) // che rappresenta gl iargomenti. // Il primo argomento e' il nome che e' stato assegnato al programma. // argc e argv possono essere omessi se non hai bisogno di argomenti, // in questa maniera la funzione avra' int main() come firma. // Lo stato di uscita 0 indica successo. return 0; } // Tuttavia, il C++ varia nei seguenti modi: // In C++, i caratteri come letterali sono da un byte. sizeof('c') == 1 // In C, i caratteri come letterali sono della stessa dimensione degli interi. sizeof('c') == sizeof(10) // C++ ha prototipizzazione rigida void func(); // funziona che non accetta argomenti // In C void func(); // funzione che puo' accettare un qualsiasi numero di argomenti // Usa nullptr invece di NULL in C++ int* ip = nullptr; // Gli header C standard sono disponibili in C++, // ma sono prefissati con "c" e non hanno il suffisso ".h". #include int main() { printf("Ciao, mondo!\n"); return 0; } /////////////////////////////// // Overloading per le funzioni ////////////////////////////// // Il C++ supporta l'overloading per le funzioni // sia dato che ogni funzione accetta parametri diversi. void print(char const* myString) { printf("Stringa %s\n", myString); } void print(int myInt) { printf("Il mio int e' %d", myInt); } int main() { print("Ciao"); // Viene chiamata void print(const char*) print(15); // Viene chiamata void print(int) } //////////////////////// // Argomenti di default /////////////////////// // Puoi fornire argomenti di default per una funzione // se non sono forniti dal chiamante. void faiQualcosaConInteri(int a = 1, int b = 4) { // fai qualcosa con gli interi qui } int main() { faiQualcosaConInteri(); // a = 1, b = 4 faiQualcosaConInteri(20); // a = 20, b = 4 faiQualcosaConInteri(20, 5); // a = 20, b = 5 } // Gli argomenti di default devono essere alla fine della lista degli argomenti. void dichiarazioneInvalida(int a = 1, int b) // Errore! { } ///////////// // Namespaces ///////////// // I namespaces forniscono visibilita' separata per dichiarazioni di variabili, funzioni, // ed altro. // I namespaces possono essere annidati. namespace Primo { namespace Annidato { void foo() { printf("Questa e' Primo::Annidato::foo\n"); } } // fine di namespace Annidato } // fine di namespace Primo namespace Secondo { void foo() { printf("Questa e' Secondo::foo\n") } } void foo() { printf("Questa e' foo globale\n"); } int main() { // Assume che tutto venga dal namespace "Secondo" // a meno che non venga dichiarato altrimenti. using namespace Secondo; foo(); // stampa "Questa e' Secondo::foo" Primo::Annidato::foo(); // stampa "Questa e' Primo::Annidato::foo" ::foo(); // stampa "Questa e' foo globale" } /////////////// // Input/Output /////////////// // L'input e l'output in C++ utilizza gli streams // cin, cout, e cerr i quali rappresentano stdin, stdout, e stderr. // << e' l'operatore di inserzione >> e' l'operatore di estrazione. #include // Include for I/O streams using namespace std; // Gli streams sono nel namespace std (libreria standard) int main() { int myInt; // Stampa su stdout (o terminalee/schermo) cout << "Inserisci il tuo numero preferito:\n"; // Prende l'input cin >> myInt; // cout puo' anche essere formattato cout << "Il tuo numero preferito e' " << myInt << "\n"; // stampa "Il tuo numero preferito e' " cerr << "Usato per messaggi di errore"; } //////////// // Stringhe /////////// // Le stringhe in C++ sono oggetti ed hanno molte funzioni membro #include using namespace std; // Anche le stringhe sono contenute nel namespace std (libreria standard) string myString = "Ciao"; string myOtherString = " Mondo"; // + e' usato per la concatenazione. cout << myString + myOtherString; // "Ciao Mondo" cout << myString + " Bella"; // "Ciao Bella" // le stringhe in C++ possono essere modificate. myString.append(" Mario"); cout << myString; // "Ciao Mario" /////////////// // Riferimenti ////////////// // Oltre ai puntatori come quelli in C, // il C++ ha i _riferimenti_. // Questi non sono tipi puntatori che non possono essere riassegnati una volta settati // e non possono essere null. // Inoltre, essi hanno la stessa sintassi della variabile stessa: // * non e' necessario per la dereferenziazione e // & ("indirizzo di") non e' usato per l'assegnamento. using namespace std; string foo = "Io sono foo"; string bar = "Io sono bar"; string& fooRef = foo; // Questo crea un riferimento a foo. fooRef += ". Ciao!"; // Modifica foo attraverso il riferimento cout << fooRef; // Stampa "Io sono foo. Ciao!" // Non riassegna "fooRef". Questo e' come scrivere "foo = bar", e // foo == "Io sono bar" // dopo questa riga. fooRef = bar; const string& barRef = bar; // Crea un riferimento const a bar. // Come in C, i valori const (i puntatori e i riferimenti) non possono essere modificati. barRef += ". Ciao!"; // Errore, i riferimenti const non possono essere modificati. ////////////////////////////////////////////////// // Classi e programmazione orientata agli oggetti ///////////////////////////////////////////////// // Primo esempio delle classi #include // Dichiara una classe. // Le classi sono in genere dichiara in un header file (.h o .hpp). class Cane { // Variabili e funzioni membro sono private di default. std::string nome; int peso; // Tutti i membri dopo questo sono pubblici (public) // finche' "private:" o "protected:" non compaiono. public: // Costruttore di default Cane(); // Dichiarazioni di funzioni membro (le implentazioni sono a seguito) // Nota che stiamo usando std::string invece di porre // using namespace std; // sopra. // Mai usare uno statement "using namespace" in uno header. void impostaNome(const std::string& nomeCane); void impostaPeso(int pesoCane); // Le funzioni che non modificano lo stato dell'oggetto // dovrebbero essere marcate come const. // Questo permette di chiamarle con un riferimento const all'oggetto. // Inoltre, nota che le funzioni devono essere dichiarate espliciamente come _virtual_ // per essere sovrascritte in classi derivate. // Le funzioni non sono virtual di default per motivi di performance. virtual void print() const; // Le funzioni possono essere definite anche all'interno del corpo della classe. // Le funzioni definite in questo modo sono automaticamente inline. void abbaia() const { std::cout << nome << " abbaia!\n"; } // Assieme con i costruttori, il C++ fornisce i distruttori. // Questi sono chiamati quando un oggetto e' rimosso o esce dalla visibilita'. // Questo permette paradigmi potenti come il RAII // (vedi sotto) // I distruttori devono essere virtual per permettere a classi di essere derivate da questa. virtual ~Dog(); }; // Un punto e virgola deve seguire la definizione della funzione // Class member functions are usually implemented in .cpp files. void Dog::Dog() { std::cout << "A dog has been constructed\n"; } // Objects (such as strings) should be passed by reference // if you are modifying them or const reference if you are not. void Dog::setName(const std::string& dogsName) { name = dogsName; } void Dog::setWeight(int dogsWeight) { weight = dogsWeight; } // Notice that "virtual" is only needed in the declaration, not the definition. void Dog::print() const { std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; } void Dog::~Dog() { cout << "Goodbye " << name << "\n"; } int main() { Dog myDog; // prints "A dog has been constructed" myDog.setName("Barkley"); myDog.setWeight(10); myDog.printDog(); // prints "Dog is Barkley and weighs 10 kg" return 0; } // prints "Goodbye Barkley" // Inheritance: // This class inherits everything public and protected from the Dog class class OwnedDog : public Dog { void setOwner(const std::string& dogsOwner) // Override the behavior of the print function for all OwnedDogs. See // http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping // for a more general introduction if you are unfamiliar with // subtype polymorphism. // The override keyword is optional but makes sure you are actually // overriding the method in a base class. void print() const override; private: std::string owner; }; // Meanwhile, in the corresponding .cpp file: void OwnedDog::setOwner(const std::string& dogsOwner) { owner = dogsOwner; } void OwnedDog::print() const { Dog::print(); // Call the print function in the base Dog class std::cout << "Dog is owned by " << owner << "\n"; // Prints "Dog is and weights " // "Dog is owned by " } ////////////////////////////////////////// // Initialization and Operator Overloading ////////////////////////////////////////// // In C++ you can overload the behavior of operators such as +, -, *, /, etc. // This is done by defining a function which is called // whenever the operator is used. #include using namespace std; class Point { public: // Member variables can be given default values in this manner. double x = 0; double y = 0; // Define a default constructor which does nothing // but initialize the Point to the default value (0, 0) Point() { }; // The following syntax is known as an initialization list // and is the proper way to initialize class member values Point (double a, double b) : x(a), y(b) { /* Do nothing except initialize the values */ } // Overload the + operator. Point operator+(const Point& rhs) const; // Overload the += operator Point& operator+=(const Point& rhs); // It would also make sense to add the - and -= operators, // but we will skip those for brevity. }; Point Point::operator+(const Point& rhs) const { // Create a new point that is the sum of this one and rhs. return Point(x + rhs.x, y + rhs.y); } Point& Point::operator+=(const Point& rhs) { x += rhs.x; y += rhs.y; return *this; } int main () { Point up (0,1); Point right (1,0); // This calls the Point + operator // Point up calls the + (function) with right as its paramater Point result = up + right; // Prints "Result is upright (1,1)" cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; return 0; } //////////////////////////// // Gestione delle eccezioni /////////////////////////// // La libreria standard fornisce un paio di tipi d'eccezioni // (vedi http://en.cppreference.com/w/cpp/error/exception) // ma ogni tipo puo' essere lanciato come eccezione #include // Tutte le eccezioni lanciate all'interno del blocco _try_ possono essere catturate dai successivi // handlers _catch_. try { // Non allocare eccezioni nello heap usando _new_. throw std::exception("E' avvenuto un problema"); } // Cattura le eccezioni come riferimenti const se sono oggetti catch (const std::exception& ex) { std::cout << ex.what(); // Cattura ogni eccezioni non catturata dal blocco _catch_ precedente } catch (...) { std::cout << "Catturata un'eccezione sconosciuta"; throw; // Rilancia l'eccezione } /////// // RAII /////// // RAII sta per Resource Allocation Is Initialization. // Spesso viene considerato come il piu' potente paradigma in C++. // E' un concetto semplice: un costruttore di un oggetto // acquisisce le risorse di tale oggetto ed il distruttore le rilascia. // Per comprendere come questo sia vantaggioso, // consideriamo una funzione che usa un gestore di file in C: void faiQualcosaConUnFile(const char* nomefile) { // Per cominciare, assumiamo che niente possa fallire. FILE* fh = fopen(nomefile, "r"); // Apri il file in modalita' lettura. faiQualcosaConUnFile(fh); faiQualcosAltroConEsso(fh); fclose(fh); // Chiudi il gestore di file. } // Unfortunately, things are quickly complicated by error handling. // Suppose fopen can fail, and that doSomethingWithTheFile and // doSomethingElseWithIt return error codes if they fail. // (Exceptions are the preferred way of handling failure, // but some programmers, especially those with a C background, // disagree on the utility of exceptions). // We now have to check each call for failure and close the file handle // if a problem occurred. bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Open the file in read mode if (fh == nullptr) // The returned pointer is null on failure. return false; // Report that failure to the caller. // Assume each function returns false if it failed if (!doSomethingWithTheFile(fh)) { fclose(fh); // Close the file handle so it doesn't leak. return false; // Propagate the error. } if (!doSomethingElseWithIt(fh)) { fclose(fh); // Close the file handle so it doesn't leak. return false; // Propagate the error. } fclose(fh); // Close the file handle so it doesn't leak. return true; // Indicate success } // C programmers often clean this up a little bit using goto: bool doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); if (fh == nullptr) return false; if (!doSomethingWithTheFile(fh)) goto failure; if (!doSomethingElseWithIt(fh)) goto failure; fclose(fh); // Close the file return true; // Indicate success failure: fclose(fh); return false; // Propagate the error } // If the functions indicate errors using exceptions, // things are a little cleaner, but still sub-optimal. void doSomethingWithAFile(const char* filename) { FILE* fh = fopen(filename, "r"); // Open the file in read mode if (fh == nullptr) throw std::exception("Could not open the file."); try { doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } catch (...) { fclose(fh); // Be sure to close the file if an error occurs. throw; // Then re-throw the exception. } fclose(fh); // Close the file // Everything succeeded } // Compare this to the use of C++'s file stream class (fstream) // fstream uses its destructor to close the file. // Recall from above that destructors are automatically called // whenever an object falls out of scope. void doSomethingWithAFile(const std::string& filename) { // ifstream is short for input file stream std::ifstream fh(filename); // Open the file // Do things with the file doSomethingWithTheFile(fh); doSomethingElseWithIt(fh); } // The file is automatically closed here by the destructor // This has _massive_ advantages: // 1. No matter what happens, // the resource (in this case the file handle) will be cleaned up. // Once you write the destructor correctly, // It is _impossible_ to forget to close the handle and leak the resource. // 2. Note that the code is much cleaner. // The destructor handles closing the file behind the scenes // without you having to worry about it. // 3. The code is exception safe. // An exception can be thrown anywhere in the function and cleanup // will still occur. // All idiomatic C++ code uses RAII extensively for all resources. // Additional examples include // - Memory using unique_ptr and shared_ptr // - Containers - the standard library linked list, // vector (i.e. self-resizing array), hash maps, and so on // all automatically destroy their contents when they fall out of scope. // - Mutexes using lock_guard and unique_lock ``` Letture consigliate: Un riferimento aggiornato del linguaggio puo' essere trovato qui Risorse addizionali possono essere trovate qui