Naming conventions are used throughout Symbian OS for a number of reasons. Most significantly, they provide important clues to the developer as to how a class, function or variable should be used. Consistent use of naming conventions also allows the use of automatic verification tools to check for coding errors in your code. Such tools will be covered further in Chapter 13.
This section introduces naming conventions that relate to classes and data. Other naming conventions that relate to methods will be introduced as you meet them later in the chapter, such as those in the Exception Handling and Resource Management section. Further information on all of the naming conventions used within Symbian OS can be found in the SDK documentation.
Class names consist of a single letter prefixed to the class name : T , S , C , R , M or N . The remainder of the class name should provide a clear indication of what the class does, with words delimited by capitalizing the first letter of each ”for example, CActiveScheduler , trect , and RArray . Note that classes that consist solely of static member functions have no prefix letter, such as User , StringLoader , and SysUtil .
One other important programming concept that is used throughout this chapter is the difference between the stack and the heap . This is not a Symbian OS-specific concept, and so to refresh your memory:
The (program) stack is a fixed- size , last-in, first-out (LIFO) area of system memory, reserved for each application. This area is where temporary data, such as local variables, are stored. At the end of each function call, all of the local variables created in that function are destroyed as the stack unwinds.
The heap is an area of memory that is dynamically allocated by the system, as needed by an application. Heap memory can be allocated or deallocated at any point during program execution ”its lifetime is controlled by the application, not the system. Heap memory is allocated (in general) using a system call such as malloc() , or in C++ using the new operator. As you will see in the section Exception Handling and Resource Management , Symbian OS requires the use of more complicated methods for allocating heap memory.
Any class prefixed with a " T " denotes a simple class that owns no heap-allocated (dynamic) memory or other resources, and so does not require an explicit destructor. Such a class may be instantiated on either the heap or stack, but bear in mind that "simple" need not mean "small." Some of these T -classes can be quite large, and it is easily possible to exceed the stack size, for instance, by instantiating a handful of TFileNames . Stack overflow is an unrecoverable error that is caught by the system and results in your application being shut down.
Also note that these classes are not merely data structures ”they can have extensive APIs. For example, trect , which is used to represent rectangular regions of the display, has a number of methods such as Width() , Height() , Shrink() and so on.
T -classes do not have a common base class, and you must ensure that each is fully constructed before use.
C++ struct s may also occasionally be used, and these are given the prefix " S ". The use of these is quite rare, however, and for the purpose of this book they can be treated as T -classes. If they are used, then such structures should not have any member functions ”a ( T -type) class should be used instead.
A " C " prefix denotes a class that derives from CBase . These classes are designed to be constructed on the heap and should not be constructed on the stack ”many have private (or protected) constructors to prevent this. The prefixed " C " denotes "Cleanup", as the implementation of CBase (particularly its virtual destructor) is integral to the memory management scheme of Symbian OS ”this will be covered in much more detail in the Exception Handling and Resource Management section of this chapter. In addition to a virtual destructor (all C -class destructors are virtual), CBase has an overloaded new operator ( new (ELeave) ) that zero-initializes all member data. Therefore it is never necessary to zero-initialize any member data for a CBase -derived object. ( This applies only to C-classes .) Examples of C -classes include CActive and CArray .
Note that any C -classes you create must derive from CBase (although not necessarily directly ”deriving from another C -class will do). Symbian OS memory management will work correctly only if all C -classes derive from CBase .
An " R " prefixed class denotes a client-side handle to a resource. This resource is not actually owned by an application, but typically by a Symbian OS Server elsewhere on the device. The client can use these handles to access the resource being managed by the Server and to request functionality of it.
In spite of some common functionality between these classes, they have no common base class. Generally they are instantiated on the stack or nested within C -classes, and then "opened" in some way (usually by a call to a method such as Open () or Connect() ). When they are finished with, it is essential to use the appropriate functionality to dispose of the class ”usually a Close() function. Failure to do so will result in memory or other resources being leaked by the server that the R -class connected to.
For example, the CElementsEngine class connects its file system session ( iFs , an RFs instance) when the class is constructed, and closes it in its destructor:
void CElementsEngine::ConstructL() { User::LeaveIfError(iFs.Connect()); } CElementsEngine::~CElementsEngine() { iFs.Close(); }
The file system will be discussed in the Files, Streams and Stores section later in this chapter. User::LeaveIfError() will be explained in the Exception Handling and Resource Management section.
Symbian OS has two main conventions for naming data: all class attributes (member data) are prefixed with a lower-case " i " (for "instance data"), as in iFs , and all function parameters are prefixed with a lower-case " a " (for "argument"). There are no conventions for automatic variables. |
Classes prefixed with " M " are mixins . They define an interface but do not provide an implementation. Such classes are Abstract Base Classes and consist of nothing but pure virtual functions. As such, they have no member data and cannot be instantiated. M -classes provide the only form of multiple inheritance used in Symbian OS ”you never derive from more than one C -class, but you can derive from as many M -classes as necessary.
M -classes are used to define a variety of interfaces throughout Symbian OS, with one of the most common uses being to implement the Observer Design Pattern , a standard way of allowing objects to communicate without tight coupling.
Design Patterns Gamma, Helm, Johnson and Vlissides Addison-Wesley ISBN: 0201633612 |
The following example is taken from the Elements application. The M -class, MCsvFileLoaderObserver , is defined with one pure virtual function:
class MCsvFileLoaderObserver { public: 0; virtual void NotifyElementLoaded(TInt aNewElementIndex) = };
In this example (with numerous functions omitted for clarity), CElementsEngine implements the MCsvFileLoaderObserver interface. It achieves this by inheriting ( publicly ) from MCsvFileLoaderObserver .
class CElementsEngine : public CBase, public MCsvFileLoaderObserver { private: // From MCsvFileLoaderObserver void NotifyElementLoaded(TInt aNewElementIndex); };
Next is a code snippet that shows how the CCsvFileLoader class uses a pointer to a MCsvFileLoaderObserver object to notify it that an element has been successfully loaded into its element list:
// Report the element that's just been loaded to the observer iObserver.NotifyElementLoaded(lastElementLoadedIndex);
By using the MCsvFileLoaderObserver mixin, the CCsvFileLoader does not have to know anything about the CElementsEngine that is observing the loading process. All the loader needs to know about is the MCsvFileLoaderObserver interface, which the engine implements.
C++ namespaces allow the packaging of components (encapsulated software modules that equate to UML component packages) to control their scope and visibility and help avoid name clashes . They are fairly new to Symbian OS, since they have only (relatively) recently been fully ratified and supported by all compilers, so you may not encounter them all that often. However, Series 60 coding standards state that namespaces should start with an " N ". Examples include NEikonEnvironment and NBitMapMethods . Generally, they are used in place of static classes, to wrap up functions that do not belong anywhere else, without polluting the global namespace. An example of a namespace declaration is shown here:
[View full width]namespace NElementComparisonFunctions { // Equality functions // (True if aElement1 == aElement2) TBool ElementsHaveSameName(const CChemicalElement& aElement1, const CChemicalElement& aElement2); TBool ElementsHaveSameSymbol(const CChemicalElement& aElement1, const CChemicalElement& aElement2); TBool ElementsHaveSameAtomicNumber(const CChemicalElement& aElement1, const CChemicalElement& aElement2); };
Before the advent of namespaces, utility classes were used to achieve the same goal. These were classes that consisted of nothing but static member functions, and they were given names such as User and Math ”without prefixed letters . You will still find these classes used throughout Symbian OS code.