===== Triedy a struktury ===== ==== Nazvy tried a struktur ==== Názvy sa tvoria výhradne z anglických slov. Ohladom nazvov pozri: [[coding:rules_k2|Nazvoslovia]] ==== Pimpl ==== Pre triedy rozhrani obsahujuce membre sa pouziva pimpl princip: [[http://c2.com/cgi/wiki?PimplIdiom|Pimpl]] ==== Triedy ==== * prefix(prvé písmeno) E Napr.: EObject (E ako EMtest) * členské premené/membre objektu m Napr.: mPrivate * každé slovo názvu premennej začína veľkým písmenom Napr.: DataCollection * Ak je trieda v namespace-y, nepouzivat v cpp namespace-y pred triedou ==== Privátne triedy ==== Kvôli čistote kódu a v prípade knižníc zabezpečovaniu binárnej kompatibility pri pridávaní členských premenných do tried je potrebné celú privátnu časť triedy zapuzdrovať do osobitnej triedy nasledovným spôsobom: (viac o binarnej kompatibilite tu: [[howto:binary_compatibility|Binarna_kompatibilita]]. Viac o tomto principe tu: [[http://c2.com/cgi/wiki?PimplIdiom|Pimpl_Idiom]]) class Class { public: Class(); ~Class(); //TODO all public members private: class DataClass; DataClass* d; }; Táto trieda je v hlavičkom súbore iba dopredne deklarovaná, definícia triedy sa nachádza v prislušnom cpp (najlepšie na začiatku) class Class::DataClass { public: //TODO all private members and methods }; Privátny member d bude alokovaný v konštruktore a dealokovaný v deštruktore Class Treba si uvedomiť, že na takúto triedu defaultny copy konštruktor už postačovať nebude, preto ho treba implementovať napríklad takto: Class::Class( const Class& rhs ) { d = new Class::DataClass( *rhs.d ); } V pripade, ze je potrebne mat pristup k majitelovi datovej triedy, je vhodne zvazit ci je naozaj potrebne tento pristup mat (moze to smerovat k zlemu dizajnu) ak ano, tak by sa premenna mala volat **mDataClassOwner**. Tento smernik nie je mozne poskytovat mimo triedy Class. class Class::DataClass { public: Class *mDataClassOwner; //other private members and methods }; === Qt5 a shared pointre === Pre projekty v standarde c++11 a Qt5 (Vesna) sa pouziva mechanizmus QSharedPointer a osobitne pre datove tiredy mechanizmus QScopedPointer. Tym sa zabezpeci automaticke mazanie datovej triedy v destruktore predka. Potom priklad vyzera nasledovne: #include class Class { public: Class(); ~Class(); //TODO all public members private: class DataClass; QScopedPointer d; }; Class::Class( ) { d.reset( new DataClass() ); // pri shared pointroch je mozny zapis: // d = QSharedPointer( new Class::DataClass() ); // ale pre vacsiu prehladnost pouzivame metodu reset(). } Class::~Class() { // do not delete DataClass } ==== Lokálne premenné ==== * názvy lokálnych premenných začínajú malým písmenom Napr.: local * každé ďalšie slovo názvu premennej začína veľkým písmenom Napr.: dataCollectionWrite * a nezabúdať na to, že medzi lokálne premenné patria aj parametre funkcií! * nedopisovať na začiatok premenných zbytočné písmenká určujúce ich dátový typ ako napríklad bool bResult; unsigned long ulNumber; a pod. (tzv maďarská notácia) ==== Enum ==== - názov enum-u začína veľkým písmenom Napr.: enum Fonts - rovnako ako pri triedach a funkciách sa používa "CamelCase", napr. enum TextHorizontalAlignmet - pre jednotlivé položky enum-u sa používa rovnaká notácia ako pre názov. Pre jednoznačnejšie názvy môžeme na začiatok názvu položky dať prefix hovoriaci do ktorého enum-u položka patrí. Napr: enum IssueState { StateDefault, StateSelected, StateConfirmed } ==== Typedef / using ==== * názov typedef-u začína veľkým písmenom Napr.: typedef list OutputDataList. * rovnako ako pri triedach a funkciách sa používa "CamelCase". * preferuje sa typedef v ramci triedy. * v novsich (C++11) standardoch sa moze pouzivat namiesto typedef aj using. * using sa odporuca pouzit v co mozno najmensom adresnom priestore (v ramci tried a vo funkciach) a iba ked to pomoze citatelnosti kodu. Napriklad pri viacnasobne vnorenych sablonach s vacsim poctom parametrov, ktore sa v ramci funkcie pouzivaju na viacerych miestach (v konstrukcii: QList< QPair< const char*, const char* > > vnutorny Pair). ==== Include-y ==== - include-y píšeme s rozsirenou relativnou cestou (od zaciatku projektu) cestou kvôli prehľadnosti .pro-súboru, kompilácia ide o trošku rýchlejšie a hlavne ak sú dva súbory s rovnakým názvom je nad slnko jasnejšie, ktorý z nich bude includnutý
#include "EXML/EXMLAttrib.h" - do hlavičkových súborov pridávať LEN nutné include-y a ako prvé systémové include-y. To znamená použiť include len v prípade, že dopredná deklarácia nefunguje. Vo všeobecnosti platí, že musí byť include na: - triedu, po ktorej aktuálna trieda dedí - triedu, ktorej inštancia je nedynamickým membrom aktuálnej triedy - stl string, stl vector (a myslim ze aj na stl mapu a list). V podstate všetky typedef-y
#ifndef _a_h_included_ #define _a_h_included_ #include #include #include "abase.h" #include "b.h" // Forward Declarations class C; class D; class A : public ABase { public: void SetC(vector *c); C *GetC() const; void ModifyD(D *d); private: std::string mName; B mB; C *mC; D *mD; }; #endif - v cpp odporúčam logicky separovať include-y do skupín (každú skupinu popísať commentom) s tým, že ako prvý má byť include na hlavičkový súbor, ktorý prislúcha danému cpp, potom na systémové .h súbory, potom na Qt, potom zvyšné a nakoniec na logy (emlog). Za include-y môžme napísať v cpp using namespace na potrebné nasmpace-y. Za porušenie strieľať nebudeme, ale je to takto prehľadnejšie.
/// HEADER INCLUDE #include "EUI.h" /// SYSTEM INCLUDES #include /// QT INCLUDES #include /// BASE INCLUDES #include "EUIDefines.h" #include "EUIDriver.h" #include "EUIDriverCreator.h" #include "EUIImplementationDirectFB.h" #include "EObject.h" /// COMMANDS INCLUDE #include "ECmdSetText.h" #include "ECmdWindowOperation.h" #include "ECmdAddWindow.h" /// XML INCLUDES #include "EXML/EXMLAttrib.h" /// DEVICESYSTEM INCLUDES #include "edevicesystem/EDriverProperties.h" /// LOGS #define __USE_LOG__ #include "emlog.h" DECLARE_LOG_OBJECT(); /// NAMESPACES using namespace EM::Devices; using namespace std; ==== Alokovanie a dealokovanie ==== Pouzitie new / malloc vs. delete / free * You have to deallocate with the operation that matches the allocation operation. When you allocate with new, you have to deallocate with delete. You have to match new[] with delete[]. You have to match malloc() with free(). And you have to match operator new with operator delete. Everything else is always undefined behaviour. * In other words: if using ::operator delete() on the void* works on your platform for PODs, delete or delete[] will probably work just as well. Doesn't change the fact that both are undefined behaviour. * The allocator objects used in the STL still follow this guideline. std::allocator uses ::operator new and ::operator delete to allocate and deallocate memory, then uses placement new and explicit destructor calls for construction and destruction. ==== Špeciality štruktúr ==== * pri štruktúrach, ktoré idú do súboru, alebo sa prenášajú cez sieť ... používať atribút packed v tvare: __attribute__ ((packed)); 32 bitovy procesor vyhradzuje 4 byte pre kazdy typ premenej nezavisle od typu (char, short, long) struct EMSKUsedTTZonesHeader { unsigned char version; //pozicia 0, dlzka 2 unsigned short headerSize; //pozicia 2, dlzka 2 unsigned long line; //pozicia 4, dlzk 4 unsigned long trip; //pozicia 8, dlzka 4 unsigned short recordSize; } __attribute__ ((packed)); * Pozor na to, ze popisane riesenie je platformovo zavisle, vo windowse sa zarovnanie stuktur na 1 byte robi nasledovne: #pragma pack( push, 1 ) typedef struct _BMP_header { unsigned short ImageFileType; unsigned long FileSize; unsigned short Reserved1; unsigned short Reserved2; unsigned long ImageDataOffset; } #pragma pack(pop) BMP_header; * Preto existuje v kniznici basedefs makro PACK, ktore umoznuje jeden zapis pre Win aj Lin. * atribut packed pouzivat len pri strukturach ku ktorym pristupujeme bajtovo problemy s packet: ak je struktura napr. Struct A { long a; char b; long c; }; a mame funkciu void funkcia(long *x) { *x = 5; } a pouzitie... A xy; funkcia(&xy.c); pri plneni premenej x (*x=5) je pointer na premenu x posahany ==== Const ==== Pravidla pouzivania a vysvetlenie pouzivania: [[http://www.parashift.com/c++-faq-lite/const-correctness.html|Const pouzivanie a vysvetlenie]]