===== 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]]