C++

C++ on ohjelmointikieli, jonka Bjarne Stroustrup kehitti 1980-luvulla. Kieli on kehitetty C-kielestä lisäämällä siihen muun muassa olio-ohjelmointiin ja geneerisyyteen liittyviä ominaisuuksia.Stroustrup 1994, s. 63–108 C++-kielen standardi ISO/IEC 14882:1998 vahvistettiin vuonna 1998, C++11 (ent. C++0x) vuonna 2011, C++14 (ISO/IEC 14882:2014) vuonna 2014, ja C++17 (ISO/IEC 14882:2017) vuonna 2017. Uusin standardiversio C++20 (ISO/IEC 14882:2020) on julkaistu vuonna 2020. C++ sisältää muun muassa luokat, virtuaalisen moniperintätuen, mallit (templates) ja poikkeukset. C++ perustuu C-kieleen siten, ettei kieltä ole suunniteltu uudelleen, vaan uusia ominaisuuksia on lisätty.Hietanen 1997, s. 16 Kieli on moniparadigmainen, mahdollistaen muun muassa proseduraalisen-, olio- ja geneerisen ohjelmoinnin.Stroustrup 2015, s. 11 Kieli ei ole täysin funktionaalisen ohjelmoinnin kieli, mutta mahdollistaa monia vastaavia käyttötapoja. Muistinhallinta perustuu RAII () -konseptiin, joka soveltuu muun muassa käyttöön poikkeuksien kanssa. C++:lla on kirjoitettu suuri osa maailman ohjelmistoista, mukaan lukien käyttöjärjestelmät, lääketieteelliset ohjelmistot, simulointiohjelmistot, finanssialan ohjelmistot, tietokoneavusteisen suunnittelun ohjelmistot, sulautetut järjestelmät, tietokoneverkot, ja videopeliohjelmistot (mm. pelimoottorit). TIOBE:n vuosittain päivittyvässä indeksissä C++ oli neljänneksi yleisin ohjelmointikieli huhtikuussa 2021.https://www.tiobe.com/tiobe-index/ == Historia ja vaikutteet == C++:n kehitys alkaa vuodesta 1979, jolloin Bjarne Stroustrup työskenteli tohtorintutkinnon parissa. Tuolloin Stroustrup työskenteli muun muassa Simula-kielellä, jonka sanotaan olevan ensimmäinen olio-ohjelmoinnin paradigmaa tukeva kieli. Stroustrup koki paradigman hyvin käytännölliseksi, mutta kielen liian hitaaksi käytännölliseen soveltamiseen. Tämän jälkeen Stroustrup aloitti C with Classes -laajennuksen kehittämisen C-kieleen. Vuonna 1983 kielen nimi vaihtui C++:ksi. C++:n luokat ja luokkahierarkia on peräisin Simulasta.Stroustrup 2015, s. 577 Kieli lainasi myös suunnitteluajattelun, jossa luokat mallintavat käsitteitä ohjelmoijan ja sovelluksen maailmassa eivätkä ainoastaan notaationaalisessa merkityksessä. Kielen suunnittelussa vältettiin ominaisuuksia, jotka aiheuttaisivat ajonaikaista tai muistikuormitusta.Stroustrup 2015, s. 15 Uudet versiot kielen standardista julkaistaan nykyään kolmen vuoden välein. Aikaisemmin uudet versiot julkaistiin kun ne olivat "valmiita", joka aiheutti pitkiä viivästyksiä ja epävarmuutta kielen käyttäjille ja soveltajille. Julkaisua muutettiin siten, että ennakolta valitaan tietty ajankohta jolloin valmiit ominaisuudet julkaistaan tuolloin ja keskeneräiset ominaisuudet jäävät myöhempään ajankohtaan, jolloin niiden parissa työskennellään muiden asioiden ohella. Kaksi vuotta on käytännön minimi ISO-standardointiprosessissa ja kolme vuotta on koettu sopivaksi balanssiksi. == Kehitysvaiheet == Kielestä on julkaistu useita kehitysversioita: * C++98 (ISO/IEC 14882:1998) oli kielen ensimmäinen ISO-standardoitu versio. * C++03 sisälsi korjauksen `std::vector` määrittelyyn, jonka mukaan elementtien käyttämä muistialue on oltava jatkuva (joka takaa yhteensopivuuden perinteisempien taulukoiden kanssa). * C++11 lisää tuen mm. säiekohtaiselle muistille (thread_local-avainsanalla) sekä säikeistykselle yleisesti.Programming Languages – C++11 Draft (n3797) §3.7.2 Thread Storage duration [basic.stc.thread] Standardikirjastoon lisättiin uudet älyosoittimet, kuten `std::shared_ptr` (toteuttaa viitelaskennan). * C++14 lisää tuen mm. lambda-funktioille eli anonyymeille inline-funktioille. * C++17 on laaja päivitys, jossa on mm. UTF-8-merkkijonoliteraalit, standardoitu tiedostojärjestelmätuki sekä standardikirjaston rinnakkaissuorituksen parantaminen. * C++20 äänestettiin valmiiksi 15. helmikuuta 2020 ja julkaistiin joulukuussa 2020. * C++23 on seuraava versio, jota kehitetään C++20:n seuraajaksi * C++26 on suunnitteilla oleva tuleva versio === ISO- standardit === C++ ISO/IEC standardista on julkaistu seuraavat versiot: * ISO/IEC 14882:1998 (1998) * ISO/IEC 14882:2003 (2003) * ISO/IEC 14882:2011 (2011) * ISO/IEC 14882:2014 (2014) * ISO/IEC 14882:2017 (2017) * ISO/IEC 14882:2020 (2020) === Tekniset määrittelyt === Virallisten standardien lisäksi ISO-työryhmällä on eräitä teknisiä määrittelyjä, jotka eivät ole vielä varsinaisen standardin tasolla ja jotka ovat vielä muuttuvia. Esimerkkinä N4514, joka määrittelee transaktiopohjaisen muistin käsittelyn tuen C++-kieleen. Osa ohjelmointikielen kääntäjistä tarjoaa kokeellisen tuen kuten esimerkiksi GCC. ISO:n julkaisemia määrittelyjä: * ISO/IEC TR 18015:2006 * ISO/IEC TR 19768:2007 * ISO/IEC TR 29124:2010 * ISO/IEC TR 24733:2011 * ISO/IEC TS 18822:2015 * ISO/IEC TS 19570:2015 * ISO/IEC TS 19841:2015 * ISO/IEC TS 19568:2015 * ISO/IEC TS 19217:2015 === Standardidokumenttien saatavuus === Virallinen standardi on saatavissa ISO:lta korvausta vastaan, mutta viimeisin työskentelyluonnos on saatavilla julkisesti ilmaiseksi. Virallisessa standardissa on korjattu kirjoitusvirheitä ja lisätty selvennyksiä. Standardidokumentit eivät ole tarkoitettu oppaaksi kielen oppimiseen, vaan ne ovat formaaleja sopimuksia kääntäjien ja standardikirjastojen kehittäjille. == Erot C:hen == Monet C-kielellä kirjoitetuista ohjelmista ovat myös kelvollista C++:aa., mutteivat kuitenkaan kaikki C:n kehittymisen aikana luotujen uusien varattujen sanojen ja tarkemman tyyppitarkistuksen vuoksi. C++ kuitenkin laajentaa C:tä huomattavasti, muun muassa nimiavaruustuella, isommalla standardikirjastolla, luokilla sekä malleilla. Sekä C- että C++-kielissä käytetään samantyyppisiä käytäntöjä parhaan suorituskyvyn saavuttamiseksi. Käytännöt vaikuttavat miten monta käskyä toiminto vaatii. Esimerkiksi paikalliset muuttujat toimivat nopeammin kuin globaalit ja tietyt tietotyypit vaativat enemmän käskyjä suorituksen aikana. Template-mallien käyttö metaohjelmointiin voi nopeuttaa suoritusta siirtämällä päätöksiä kääntäjälle. Template-mallit ovat C++:n monimutkaisempia ominaisuuksia, joiden yksi tarkoitus on vähentää toistuvaa koodia. Ne mahdollistavat käännösaikaisen laskennan, jolloin ajonaikaisesti ei tarvitse suorittaa ohjelmakoodia. Suorituskyky riippuu ohjelman toteutustavasta ja virheellinen toteutus voi olla hitaampi ja viedä enemmän muistia kun taas oikealla toteutuksella voi saada moninkertaisia parannuksia. == Standardikirjastot == C++ sisältää Standard Template Library (STL) -standardikirjaston. Se sisältää yleisiä ohjelmoijien tarvitsemia säiliöitä (containers), algoritmeja, funktioita ja iteraattoreita. STL-toteutus tulee yleensä kääntäjän mukana, mutta myös riippumattomia toteutuksia on olemassa. C++:n standardikirjasto sisältää STL:n lisäksi myös suurimman osan C-kielen standardikirjastosta yhteensopivuuden vuoksi. == Polymorfismi == C++ tukee yksinkertaista perintää, abstrakteja pure virtual -luokkia, moniperintää sekä virtuaalista moniperintää. Rajapinnan perimistä kutsutaan ajonaikaiseksi polymorfismiksi (tai dynaamiseksi polymorfismiksi) ja template-mallien tukemaa käännösaikaiseksi polymorfismiksi (tai staattiseksi polymorfismiksi).Stroustrup 2015, s. 578 C++:ssa funktiot voidaan määritellä:Stroustrup 2015, s. 307 * `virtual`, jolloin se voidaan syrjäyttää perityssä luokassa * `override`, jolloin sen on pakko syrjäyttää kantaluokassa oleva * `final`, jolloin sitä ei voida syrjäyttää perityssä luokassa == Hello, World! -esimerkkiohjelma == #include int main() { std::cout << "Hello, world! "; } Tämä on yleisesti käytetty esimerkkiohjelma C++-oppaissa. Se tulostaa näytölle tekstin ”Hello, world!” Kuten C:ssä, ohjelma alkaa komennoilla esikääntäjälle, tässä otsikkotiedoston liittämisellä `#include`-käskyllä. Lohkot rajataan aaltosuluilla {} ja ohjelma suoritetaan kutsumalla `main`-funktiota. Ohjaamalla teksti cout-olioon <<-operaattorilla teksti tulostuu stdout-virtaan (näytölle). C++:n tulostuslauseen epätavallinen syntaksi johtuu kielen tukemasta operaattorien uudelleenmäärittelystä. C-kielen bittisiirto-operaattori << on C++:ssa määritelty virtaolioilla kirjoitusoperaattoriksi, ja tässä tapauksessa se kirjoittaa standarditulosteeseen. C++:n kielioppi on samantapaista kuin C:n ja Javan. Lauseet päättyvät puolipisteeseen ;, eikä välilyöntejä tai muuta tyhjää tilaa oteta huomioon. Lohkot ympäröidään aaltosulkeilla { }, kommentit aloitetaan /* -merkinnällä ja päätetään */ -merkinnällä. Yhden rivin kommentti merkitään kahdella vinoviivalla //. Kaikki standardikirjaston luokat, funktiot ja enumeraatiot ovat `std`-nimiavaruudessa. == Nimiavaruudet == C++ tukee useaa nimiavaruutta. C++17 lisäsi tuen sisäkkäisille nimiavaruuksille, joka mahdollistaa `namespace A::B::C {}` käytön aiemman `namespace A { namespace B { namespace C {}}}` sijaan. Lisäksi kieli tukee nimiavaruuden aliasointia: namespace foo { namespace bar { namespace baz { int qux = 42; } } } namespace fbz = foo::bar::baz; int main() { std::cout << fbz::qux << ' '; } C++ tukee myös anonyymejä nimiavaruuksia. Aaltosuluilla merkittävät lohkot luovat oman nimiavaruuden kaltaisen näkyvyysalueen (): std::string foo = "foo"; { std::string foo = "foobar"; } // sisempi foo tuhotaan tässä std::cout << foo << std::endl; // tulostaa ensimmäisen foo:n arvon == RTTI == Ajonaikainen tyyppitieto () on ominaisuus, jolla välitetyn olion tyyppi voidaan tunnistaa ohjelman ajon aikana. Tämä mahdollistaa muun muassa perityn olion tyypin mukaisen käsittelyn. class Asiakas { public: virtual ~Asiakas() {} } class KantaAsiakas : public Asiakas { ... }; void tyyppi(Asiakas *p) { std::cout << typeid(*p).name() << std::endl; // tulostaa olion p tyypin nimen. tarkka muoto riippuu kääntäjästä. KantaAsiakas *k = dynamic_cast(p); if (k != nullptr) k->bonus(); } == Poikkeusten käsittely == C++ tukee poikkeuksia ja pinon (stack) siivoamista (kuten näkyvyysalueelta eli scopesta poistuessa). try { throw "vikatilanne"; // const char * } catch (std::exception &e;) { std::cout << "poikkeus: " << e.what() << std::endl; } catch (...) { std::cout << "tuntematon poikkeus" << std::endl; } Poikkeuskäsittelijä valitaan määrittelyjärjestyksessä ja tyypin mukaan.Stroustrup 2015, s. 370 Poikkeuskäsittely `try`-lohkolla ja `throw`-operaattorilla on valinnaista, jolloin niiden aiheuttama lisäkuorma voidaan välttää. Ellipsis (kolme pistettä) voi vastaanottaa tyypit, joille ei ole määritelty muuta käsittelijää. == RAII == Konseptia, jossa resurssit varataan konstruktorissa ja vapautetaan destruktorissa, kutsutaan nimellä . Konseptin ovat kehittäneet Bjarne Stroustrup ja Andrew Koenig vuosina 1984–1989 ja se on esitelty ensimmäisenä C++-kielessä.Stroustrup, Bjarne 2015: The C++ Programming Language, 4th ed: kpl13, s. 343–387 RAII-muistihallintakonsepti voidaan esittää seuraavan triviaalin esimerkin avulla:Stroustrup, Bjarne 2015: The C++ Programming Language, 4th ed: kpl3, s. 63 class Vector { private: double *elem; int sz; public: Vector(int s) : elem{new double[s]}, sz{s} // constructor { for (int i = 0; i != s; ++i) elem[i] = 0; } ~Vector() { delete [] elem; } // destructor double& operator[] (int i) { return elem[i]; }; int size() const { return sz; } }; void fct(int n) { Vector v(n); // acquire and initialize // .. use v .. { Vector v2(n*2); // acquire and initialize // .. use v2 .. } // v2 destroyed // .. use v .. } // v destroyed Esimerkissä resurssit vapautetaan kutsumalla olion destruktoria: # poikkeustapauksessa # normaalisti poistuessa (näkyvyysalueen ulkopuolella) Olion luominen tekee tarvittavan varauksen ja alustuksen, jotka olion destruktori vapauttaa. Menetelmä on poikkeusturvallinen eikä tarvitse roskienkeräystä tueksi. == Template-mallit == C++ tukee suoraan geneeristä ohjelmointia template- malleilla, joille voidaan antaa tyyppi parametrina.Stroustrup 2015, s. 665 Mallit mahdollistavat geneerisen ohjelmoinnin, jossa samoja algoritmeja voidaan käyttää uusille tietotyypeille ilman erillisen toteutuksen kirjoittamista joka tyypille. RAII-esimerkin ohjelmakoodi voidaan muokata geneerisemmäksi käyttämällä template-määrittelyä. template class Vector { private: T *elem; int sz; public: Vector(int s) : elem{new T[s]}, sz{s} // constructor { for (int i = 0; i != s; ++i) elem[i] = 0; } ~Vector() { delete [] elem; } // destructor T& operator[] (int i) { return elem[i]; } int size() const { return sz; } }; void fct(int n) { Vector v(n); // acquire and initialize // .. use v .. Vector v2(n) // .. use v2 .. } // v2 and v destroyed == Lambda-lausekkeet == Lambda-lausekkeet ovat C++11:stä lähtien tuettu ominaisuus anonyymien funktioiden määrittelyyn niiden käyttökohdan yhteydessä. Lambda-lausekkeet ovat muutaman rivin pituisia toimintoja, jotka välitetään algoritmeille ja asynkronisille toiminnoille. Lambda-lausekkeiden kaappausta on muutettu yleistetyksi C++14:stä. Esimerkki: // esimerkki määrittelystä auto glambda = [](auto a, auto&& b) { return a < b; }; bool b = glambda(3, 3.14); // kutsuminen == Katso myös == * SystemC – C++ -pohjainen laitteistokuvauskieli ==Lähteet== * * * * * * * * * * ===Viitteet=== ==Kirjallisuutta== * * * == Aiheesta muualla == * Programming:C plus plus Wikibook, C++-opas * Thinking in C++ , kattava ilmainen e-kirja C++:sta * C++ opas, laaja Suomenkielinen C++ opas. * C++ Standards Committee Papers * C++17 Working Draft * C++ Core Guidelines * Luokka:Seulonnan keskeiset artikkelit