T-76.115 Tietojenkäsittelyopin ohjelmatyö Sisältö Tässä dokumentissa kuvataan Keimo-projektissa sovellettavia ohjelmointikäytäntöjä. Päivämäärä 10.11.2002 Projektiryhmä Keimo keimo-dev@list.hut.fi Kirjoittajat Iiro Ojala iaojala@cc.hut.fi Muutokset PVM Tekijä Versio Selitys 10.11.2002 Iiro Ojala 0.1 Alustava versio 18.11.2002 Iiro Ojala 0.2 Versio sisäiseen katselmointiin 20.11.2002 Iiro Ojala 0.3 Katselmoinnissa päätetyt muutokset 30.11.2002. Iiro Ojala 1.0 Palautukseen valmis versio 1
Sisällysluettelo 1 Johdanto... 3 2 Nimeämiskäytännöt... 3 2.1 Luokat... 3 2.2 Funktiot... 3 2.2.1 Yleiset funktiot... 3 2.2.2 Aksessorit (setterit ja getterit)... 3 2.3 Muuttujat... 4 2.3.1 Paikalliset muuttujat... 4 2.3.2 Osoitinmuuttujat... 4 2.3.3 Viittausmuuttujat... 4 2.3.4 Vakiomuuttujat... 4 2.3.5 Jäsenmuuttujat... 5 2.3.6 Staattiset jäsenmuuttujat... 5 2.3.7 Globaalit muuttujat... 5 2.4 Enumeraatiot... 5 3 Tyyliohjeita... 6 3.1 Välilyöntien käyttö... 6 3.2 Tabulaattorin leveys... 6 3.3 Rivin katkaiseminen... 6 3.4 Aaltosulkeiden sijoittelu... 6 3.5 Aaltosulkeiden käyttö yksirivisissä lohkoissa... 7 4 Joitakin C++-ohjelmointikäytäntöjä... 8 4.1 Kopiokonstruktori ja sijoitusoperaattori... 8 4.2 Virtuaalifunktiot... 8 4.3 #define direktiivi... 8 4.4 const määre... 8 4.5 C -Structit... 8 4.6 Ystäväluokat... 9 4.7 Ystäväfunktiot... 9 4.8 Yksityinen perintä... 9 4.9 Moniperintä... 9 4.10 Lähdekooditiedostot... 9 5 C++-luokan esimerkkimäärittely... 10 2
1 Johdanto Dokumentissa kuvataan Keimo-projektissa sovellettava ohjelmointityyli sekä joitakin ohjelmointikäytäntöjä. Yhteisten sääntöjen tarkoitus on helpottaa koodin luettavuutta ja siten nopeuttaa ohjelman jatkokehitystä ja ylläpitöa. Dokumenttia täydennetään projektin kuluessa aina tarpeen niin vaatiessa. Kaikkien ohjelmoijien tulee noudattaa dokumentissa esitettyjä sääntöjä. Tyylin noudattamista kontrolloidaan koodikatselmuksissa, joissa tämä dokumentti toimii tyylitarkistuslistana. Ohjeen nimeämiskäytäntöjä ja yleisiä tyyliohjeita koskevia lukuja 2 ja 3 sovelletaan projektissa sellaisenaan C++-kieliseen ja soveltuvilta osin Javakieliseen ohjelmointiin. Joitakin tärkeitä vain C++-kielistä ohjelmointia koskevia käytäntöjä on kirjattu lukuun 3. 2 Nimeämiskäytännöt 2.1 Luokat Luokan nimi kirjoitetaan isolla alkukirjaimella. Alaviivoja ei käytetä ja sanavälit ilmoitetaan isolla alkukirjaimella. class CameraManager ; 2.2 Funktiot 2.2.1 Yleiset funktiot Funkton nimi kirjoitetaan pienellä alkukirjaimella. Alaviivoja ei käytetä ja sanavälit ilmoitetaan isolla alkukirjaimella. Paluuarvon tietotyyppiä ei ilmoiteta funktion nimessä. calculaterotationangle(); 2.2.2 Aksessorit (setterit ja getterit) 3
Aksessori nimetään kuten yleinen funktio ja sen nimi noudattaa yksinkertaista kaavaa: Attribuutin arvon asettavan jäsenfunktion nimi on muotoa set + attribuutin nimi. Attribuutin arvon palauttavan funktion nimi on muotoa get + attribuutin nimi, tai mikäli attribuutti (ja funktion paluuarvo) on totuusarvotyyppinen, is + attribuutin nimi. bool setrotationangle( angle); getrotationangle(void); isvalid(); 2.3 Muuttujat 2.3.1 Paikalliset muuttujat Paikallisen muuttujan nimi kirjoitetaan pienellä alkukirjaimella. Alaviivoja ei käytetä ja sanavälit ilmoitetaan isolla alkukirjaimella. Muuttujan tietotyyppiä ei ilmoiteta muuttujan nimessä. int index = 0; rotationangle = 0.0; 2.3.2 Osoitinmuuttujat Osoitinmuuttuja nimetään kuten paikallinen muuttuja ja sen nimen alkuun lisätään pieni p jokaista osoitintasoa kohden. Kirjainta seuraava sana kirjoitetaan isolla alkukirjaimella. int *pindex; **pprotationangle; 2.3.3 Viittausmuuttujat Viittausmuuttuja nimetään kuten paikallinen muuttuja ja sen nimen alkuun lisätään pieni r. Kirjainta seuraava sana kirjoitetaan isolla alkukirjaimella. int &rindex; &rrotationangle; 2.3.4 Vakiomuuttujat 4
Vakiomuuttujan koko nimi kirjoitetaan isoilla kirjaimilla ja sanaväli ilmoitetaan alaviivalla. const int MAX_ROUNDS = 255; 2.3.5 Jäsenmuuttujat Jäsenmuuttuja nimetään kuten paikallinen muuttuja ja sen nimen alkuun lisätään liite m_. Liittettä seuraa pieni kirjain. int m_index; *m_protationangle; 2.3.6 Staattiset jäsenmuuttujat Staattinen jäsenmuuttuja nimetään kuten paikallinen muuttuja ja sen nimen alkuun lisätään m_-liitteen sijasta liite s_. Liittettä seuraa pieni kirjain. static int s_referencecount; 2.3.7 Globaalit muuttujat Globaali muuttuja nimetään kuten paikallinen muuttuja ja sen nimen alkuun lisätään liite g_. Liittettä seuraa pieni kirjain. Globaalien muuttujien näkyvyyttä rajoitetaan aina static-määreellä. static int g_isconnectionalive; 2.4 Enumeraatiot Enumeraation tyyppinimi kirjoitetaan isolla alkukirjaimella. Alaviivoja ei käytetä ja sanavälit ilmoitetaan isolla alkukirjaimella. Enumeraation nimetyt arvot kirjoitetaan kokonaan isoilla kirjaimilla ja sanaväli ilmoitetaan alaviivalla. Julkisten enumeraatioiden nimetyissä arvoissa pitää käyttää kirjaston tai packagen nimestä johdettua etuliitettä, paikallisten ei. enum ObjectState RND_OBJECT_NOT_FOUND, RND_OBJECT_LOADED, RND_OBJECT_NOT_LOADED, 5
enum ColorType COLOR, BLACK_AND_WHITE 3 Tyyliohjeita 3.1 Välilyöntien käyttö Välilyöntiä käytetään erottamaan kaikkia moniargumenttisia operaattoreita argumenteistaan. Kuitenkin Pilkkua ennen ei tule ja sen jälkeen tulee välilyöti. Välilyöntiä ei käytetä erottamaan yksiargumettisia operaattoreita argumentistaan, eikä esimerkiksi indeksiä indeksointioperaattorista. Välilyöntiä ei yleensä käytetä ennen eikä jälkeen kaarisulkua, ellei sen käyttöä kulloinkin kyseessäolevaan tilanteeseen ole erikseen määritelty. 3.2 Tabulaattorin leveys Sisennyksessä käytettävä tabulaattorin leveys on neljä merkkiä. Sisennykset kirjoitetaan tiedostoon tab-merkkeinä(ei konvertoida välilyönneiksi). 3.3 Rivin katkaiseminen Rivi katkaistaan aina moniargumenttisen operaattorimerkin jälkeen ja operaattorin argumentit sisennetään aina samalle tasolle. Yksiargumenttisia operaattoireita ei koskaan eroteta argumentistaan. if(((count + offset) >= (limiters + offset * *plength)) && isvalid())... 3.4 Aaltosulkeiden sijoittelu Aaltosulje kirjoitetaan C++-koodissa aina omalle rivilleen. Lohkon aloittava sulje tulee edellisen rivin kanssa samalle tasolle ja lohkon koodi sisennetään yhden 6
tabulaattorin verran. Lohkon päättävä sulje tulee samalle tasolle lohkon avaavan sulun kanssa. Kyseessä on siis Allman/BSD nimellä tunnettu tyyli. Java-koodissa noudatetaan pääsääntöisesti Sunin julkaisemia Javatyyliohjeita. Ohjeet eivät ota otaa kantaa aaltosulkeiden sijoitteluun, mutta kaikki Sunin toimittama esimerkkimateriaali on muotoiltu noudattaen K&R/One True Brace tyyliä. Tyylin mukaan lohkon avaavan sulkeen paikka on edellisen rivin lopussa. Projektin Java-koodissa voidaan käyttää kumpaa tahansa mainituista tyyleistä, mutta valittua tyyliä tulee käyttää yhtenäisesti koko laadittavassa modulissa. bool validate(void)... boolean validate()... 3.5 Aaltosulkeiden käyttö yksirivisissä lohkoissa Yksirivisten lohkojen ympärillä ei normaalisti käytetä aaltosulkeita. Poikkeuksena tähän on if else if -... - else lause, jossa kaikkien lohkojen ympärillä käytetään sulkeita, mikäli yksikin lohkoista on monirivinen. Aaltosulkuja harkittaessa moniriviseksi katsotaan myös rivi, joka on muotoilu syistä katkaistu useammalle kuin yhdelle riville. if(m_isvalid) m_index++; else validator->validate(this); if(m_isvalid) m_index++; else validator->validate(this); m_index++; m_isvalid = true; while(isvalid()) applyparameters(index, lengtharray); 7
4 Joitakin C++-ohjelmointikäytäntöjä 4.1 Kopiokonstruktori ja sijoitusoperaattori Jokaiselle luokalle tulee määritellä kopiokonstruktori ja sijoitusoperaattori(=operaattori). Mikäli luokasta ei ole tarkoitus muodostaa kopioita, tai toiminnallisuutta ei vielä tarvita ja se siksi jätetään toteuttamatta, kopiokonstruktori ja sijoitusoperaattori määritellään yksityisiksi. 4.2 Virtuaalifunktiot Mikäli aliluokka korvaa yläluokkansa virtuaalifunktion, tulee funktio merkitä virtuaaliseksi myös aliluokan määrittelyssä. Yksityisten jäsenfunktioiden ei tulisi koskaan olla virtuaalisia. 4.3 #define direktiivi #define direktiivillä ei tule määritellä toiminnallisia makroja eikä symbolisia vakioita. Näiden sijasta tulee käyttää inline funktioita ja vakiomuuttujia. Sen sijaan #define:a tulee käyttää estämään saman headerin sisällyttäminen useamman kuin yhden kerran yhteen käännösyksikköön. 4.4 const määre Kaikki luokkien vakiofunktiot tulee merkitä const-funktioiksi. Mikäli luokan jäsenfunktiota ei ole merkitty const:ksi, se oletusarvoisesti mutatoi luokan tietoja. Myös kaikki funktioiden osoitin- ja viittausarvoiset vakioparametrit tulee merkitä const:ksi. Jos osoitin tai viittaus ei ole const, funktio oletusarvoisesti muuttaa sen sisältöä. Tämä on erityisen tärkeää julkisissa rajapinnoissa. 4.5 C -Structit C-tyylisiä structeja voi käyttää niille sopivissa paikoissa. Structeissa ei saa käyttää jäsenfunktioita, perintää, eikä muita kuin julkisia ei staattisia jäsenmuuttujia. Myöskään m_ -liitettä ei käytetä structin jäsenmuuttujien nimissä. Mikäli näitä ominaisuuksia tarvitaan, tulee toiminnallisuus kirjoittaa luokan muotoon. struct Point3d 8
; x; y; z; 4.6 Ystäväluokat Ystäväluokkien käyttöä tulee välttää. Yleensä niiden sijasta tulee käyttää julkisia aksessoreja ja tarvittaessa ystäväfunktioita. 4.7 Ystäväfunktiot Ystäväfunktioita tulee käyttää harkiten. Luokan ulkopuoliset itsenäiset ystäväfunktiot esitellään vain luokan esittelyn yhteydessä ja niiden toteutus kirjoitetaan luokan toteutuksen kanssa samaan tiedostoon. Luokan ystävä- ja toisen luokan jäsenfunktiota ei yleensä tule käyttää julkisissa rajapinnoissa. Perustellusta syystä niitä voi käyttää komponenttien sisäisissä toteutuksissa. 4.8 Yksityinen perintä Yksityistä perintää tulee välttää. Normaalisti sen sijasta voi käyttää joko kompositiota tai julkista perintää. 4.9 Moniperintä Kompleksisten luokkien moniperintää tulee käyttää erittäin harkiten. Virtuaalista perintää tulee käyttää aina, jos ilman sitä tuloksena olisi ns. timanttihierarkkia. Moniperintää voi käyttää Javan interfaceja vastaavan toiminnallisuuden aikaansaamiseksi. 4.10 Lähdekooditiedostot Tiedostonimen pääte valitaan seuraavasti: Tyyppi Pääte C++-lähdekoodi.cpp C++-header.hpp C-lähdekoodi.c C-header.h 9
5 C++-luokan esimerkkimäärittely class String public: String(); String(const char *pchars); ~String(); private: String(const String &rstring); String &operator=(const String &); ; // to be continued... 10