Symbian OS Explained - Effective C++ Programming For Smartphones (2005) (779885), страница 6
Текст из файла (страница 6)
CBasealready provides a virtual destructor, and nothing else, so is ideal fordefining an interface class where its implementation classes can be limited to C classes. Of course, in these cases, the implementation classeswill be limited to single inheritance, because, as I described above,multiple inheritance from CBase results in ambiguity and the dreaded”diamond-shape” inheritance hierarchy.In general, a mixin interface class should not be concerned withthe implementation details of ownership. If it is likely that callers willown an object through a pointer to the M class interface, as describedabove, you must certainly provide a means for the owner to relinquishit when it is no longer needed.
However, this need not be limited tocleaning up through a destructor. You may instead provide a pure virtualRelease() method so the owner can say ”I’m done” – it’s up to theimplementing code to decide what this means (for a C class, the functioncan just call ”delete this”). This is a more flexible interface – theimplementation class can be stack- or heap-based, perform reference3The correct class definition isclass CCat : public CBase, public MDomesticAnimal{...};and notclass CCat : public MDomesticAnimal, public CBase{...};The ”flavor” C class must always be the first specified class of the base class list, toemphasize the primary inheritance tree.
It also enables C class objects of derived classes suchas these to be placed on the cleanup stack using the correct CleanupStack::PushL()overload (see Chapter 3 for more details).BUYER BEWARE11counting, special cleanup or whatever. By the way, it isn’t essential tocall your cleanup method Release() or Close(), but it can help yourcallers if you do. First of all, it’s recognizable and easy enough to guesswhat it does. More importantly, it enables the client to make use of theCleanupReleasePushL() function described in Chapter 3.Like a Java interface, an M class should usually have only purevirtual functions. However, there may be cases where non-pure virtualfunctions may be appropriate. A good example of this occurs when all theimplementation classes of that interface have common default behavior.Adding a shared implementation to the interface reduces code duplicationand its related bloat and maintenance headaches.
Of course, there’s arestriction on what this default implementation can do, because themixin class must have no member data. Typically, all virtual functions areimplemented in terms of calls to the pure virtual functions of the interface.An M class has similar characteristics to a Java interface. It hasno member data and no constructor. The use of multiple interfaceinheritance using M classes is the only form of multiple inheritanceencouraged on Symbian OS.1.6 Static ClassesWe’ve reached the end of the naming convention prefixes, though notquite the end of the types of class commonly found on Symbian OS.There are a number of classes, with no prefix letter, that provide utilitycode through a set of static member functions, for example, User andMem.
The classes themselves cannot be instantiated; their functions mustinstead be called using the scope resolution operator:User::After(1000); // Suspends the current thread for 1000 microsecondsMem::FillZ(&targetData, 12); // Zero-fills the 12-byte block starting// from &targetDataClasses which contain only static functions do not need to have aname prefix.1.7 Buyer BewareIt’s a good rule of thumb that for all rules there are exceptions. The classname conventions on Symbian OS are no exception to that rule and there12CLASS NAME CONVENTIONS ON SYMBIAN OSare classes in Symbian OS code itself which do not fit the ideals I’ve putto you above.
There are a few classes in Symbian OS which don’t evenconform to the naming conventions. Two well-documented exceptionsare the kernel-side driver classes and the heap descriptor (HBufC), whichis discussed further in Chapter 5.This doesn’t mean that the code is wrong – in many cases there aregood reasons why they do not fit the theory. In the lower-level code, inparticular, you’ll find cases which may have been written before the nameconventions were fully established or which, for efficiency reasons, havedifferent characteristics and behavior.
Whenever you come across a newclass, it’s worth comparing it to the rules above to see if it fits and, if not,considering why it doesn’t. You’ll be able to add a set of good exceptionsto the rules to your list of cunning Symbian OS tricks, while discardingany code that unnecessarily contravenes the conventions – thus learningfrom others’ mistakes.1.8 SummaryThis chapter reviewed the major class types used when coding forSymbian OS, and described their main features such as any specialrequirements when constructing or destroying objects of the class,whether they can be stack- or heap-based and typical member datacontained by the class (if any).
In particular, the chapter discussed theuse of the class name conventions to indicate the cleanup characteristicsof objects of the class in the event of a leave.The guidelines within this chapter should be useful when writing aclass – they can help you save time when coding and testing it, if only bycutting down on the rewrite time. If you can stick as closely as possibleto Symbian OS conventions, your clients will know how you mean yourclass to be constructed, used and destroyed.
This naturally benefits them,but can also help you reduce documentation and support-time furtherdown the track.2Leaves: Symbian OS ExceptionsGo away. I’m all rightSaid to be the last words of H. G. WellsSymbian OS was first designed at a time when exceptions were not partof the C++ standard. Later, exception handling was introduced to thestandard, but was found to add substantially to the size of compiled codeand to run-time RAM overheads, regardless of whether or not exceptionswere actually thrown.
For these reasons, standard C++ exception handlingwas not considered suitable to add to Symbian OS, with its emphasis ona compact operating system and client code. When compiling SymbianOS code, the compilers are explicitly directed to disable C++ exceptionhandling, and any use of the try, catch or throw keywords is flaggedas an error.An alternative to conventional, but rather awkward, error-checkingaround each function with a return value was needed.
Thus ”leaves”1were developed as a simple, effective and lightweight exception-handlingmechanism which has become fundamental to Symbian OS. You’llencounter lots of ”leaving code” when working on Symbian OS andyou’ll probably write some too. You need to know how to recognizecode that leaves and how to use it efficiently and safely, since it’s possibleto leak memory inadvertently in the event of a leave. So when and howdoes a leave occur and why would you use it?2.1 Leaving FunctionsA leave may occur when you call a leaving function or if you explicitlycall a system function to cause a leave. A leave is used to raise an1”Leaves” is as in the verb ”to leave” rather than the noun usually found attached toplants. A function that contains code which may leave is called a ”leaving function” whilecode that has executed along the path of a leave (say, as the result of an exceptionalcondition) can be said to have ”left”.14LEAVES: SYMBIAN OS EXCEPTIONSexception and propagate an error value back up the call stack to a pointat which it can be ”caught” by a trap harness and handled appropriately.To all intents and purposes, code execution ends at the point of the leaveand resumes where it is trapped.
The leave sets the stack pointer to thecontext of a trap harness TRAP macro and jumps to the desired programlocation, restoring the register values. It does not terminate the flow ofexecution (unlike an assertion, which is used to detect programmingerrors and panic accordingly, as described in detail in Chapter 16).TRAP and User::Leave() may be considered analogous to thestandard library setjmp() and longjmp() methods respectively.
Acall to setjmp() stores information about the location to be ”jumpedto” in a jump buffer, which is used by longjmp() to determine thelocation to which the point of execution ”jumps”. A leave should only beused to propagate an exception to a point in the code which can handleit gracefully, unwinding the call stack as it does so. It should not be usedto direct the normal flow of program logic.A typical leaving function is one that performs an operation that isnot guaranteed to succeed, such as allocation of memory, which mayfail under low memory conditions. Since leaving functions by definitionleave with an error code (a ”leave code”), they do not also need to returnerror values.