- •Contents
- •1.1 Fundamental Types
- •1.2 T Classes
- •1.3 C Classes
- •1.4 R Classes
- •1.5 M Classes
- •1.6 Static Classes
- •1.7 Buyer Beware
- •1.8 Summary
- •2 Leaves: Symbian OS Exceptions
- •2.1 Leaving Functions
- •2.3 Constructors and Destructors
- •2.4 Working with Leaving Functions
- •2.5 Trapping a Leave Using TRAP and TRAPD
- •2.6 LeaveScan
- •2.7 Summary
- •3 The Cleanup Stack
- •3.1 Using the Cleanup Stack
- •3.2 How Does the Cleanup Stack Work?
- •3.4 Using TCleanupItem for Customized Cleanup
- •3.5 Portability
- •3.6 An Incidental Note on the Use of Casts
- •3.7 Summary
- •5 Descriptors: Symbian OS Strings
- •5.3 Pointer Descriptors
- •5.4 Stack-Based Buffer Descriptors
- •5.5 Heap-Based Buffer Descriptors
- •5.6 Literal Descriptors
- •5.7 Summary
- •6 Good Descriptor Style
- •6.1 Descriptors as Parameters and Return Types
- •6.2 Common Descriptor Methods
- •6.3 The Use of HBufC Heap Descriptors
- •6.4 Externalizing and Internalizing Descriptors
- •6.5 The Overuse of TFileName
- •6.6 Useful Classes for Descriptor Manipulation
- •6.7 Summary
- •7 Dynamic Arrays and Buffers
- •7.1 CArrayX Classes
- •7.3 Why Use RArray Instead of CArrayX?
- •7.4 Dynamic Descriptor Arrays
- •7.5 Fixed-Length Arrays
- •7.6 Dynamic Buffers
- •7.7 Summary
- •8.1 Multitasking Basics
- •8.2 Event-Driven Multitasking
- •8.3 Working with Active Objects
- •8.4 Example Code
- •8.5 Threads Without an Active Scheduler
- •8.6 Application Code and Active Objects
- •8.7 Summary
- •9 Active Objects under the Hood
- •9.1 Active Object Basics
- •9.2 Responsibilities of an Active Object
- •9.3 Responsibilities of an Asynchronous Service Provider
- •9.4 Responsibilities of the Active Scheduler
- •9.5 Starting the Active Scheduler
- •9.6 Nesting the Active Scheduler
- •9.7 Extending the Active Scheduler
- •9.8 Cancellation
- •9.9 Request Completion
- •9.10 State Machines
- •9.11 Long-Running Tasks
- •9.14 Common Mistakes
- •9.15 Summary
- •10 Symbian OS Threads and Processes
- •10.2 Thread Priorities
- •10.3 Stopping a Running Thread
- •10.5 Exception Handling
- •10.6 Processes
- •10.7 Summary
- •11.2 How Do the Client and Server Fit Together?
- •11.3 How Do the Client and Server Communicate?
- •11.5 How Do Synchronous and Asynchronous Requests Differ?
- •11.6 How Is a Server Started?
- •11.7 How Many Connections Can a Client Have?
- •11.8 What Happens When a Client Disconnects?
- •11.9 What Happens If a Client Dies?
- •11.10 What Happens If a Server Dies?
- •11.15 How Many Outstanding Requests Can a Client Make to a Server?
- •11.16 Can Server Functionality Be Extended?
- •11.17 Example Code
- •11.18 Summary
- •12.2 Client Boilerplate Code
- •12.3 Starting the Server and Connecting to It from the Client
- •12.4 Server Startup Code
- •12.5 Server Classes
- •12.6 Server Shutdown
- •12.7 Accessing the Server
- •12.8 Summary
- •13 Binary Types
- •13.1 Symbian OS EXEs
- •13.2 Symbian OS DLLs
- •13.3 Writable Static Data
- •13.4 Thread-Local Storage
- •13.5 The DLL Loader
- •13.6 UIDs
- •13.8 Summary
- •14 ECOM
- •14.1 ECOM Architecture
- •14.2 Features of an ECOM Interface
- •14.3 Factory Methods
- •14.4 Implementing an ECOM Interface
- •14.5 Resource Files
- •14.6 Example Client Code
- •14.7 Summary
- •15 Panics
- •15.2 Good Panic Style
- •15.3 Symbian OS Panic Categories
- •15.4 Panicking Another Thread
- •15.5 Faults, Leaves and Panics
- •15.6 Summary
- •16 Bug Detection Using Assertions
- •16.3 Summary
- •17 Debug Macros and Test Classes
- •17.1 Heap-Checking Macros
- •17.2 Object Invariance Macros
- •17.3 Console Tests Using RTest
- •17.4 Summary
- •18 Compatibility
- •18.1 Forward and Backward Compatibility
- •18.2 Source Compatibility
- •18.3 Binary Compatibility
- •18.4 Preventing Compatibility Breaks
- •18.5 What Can I Change Without Breaking Binary Compatibility?
- •18.6 Best Practice: Planning for Future Changes
- •18.7 Compatibility and the Symbian OS Class Types
- •18.8 Summary
- •19 Thin Templates
- •20.1 Class Layout
- •20.3 Parameters and Return Values
- •20.4 Member Data and Functional Abstraction
- •20.5 Choosing Class, Method and Parameter Names
- •20.7 Summary
- •21 Good Code Style
- •21.1 Reduce the Size of Program Code
- •21.2 Use Heap Memory Carefully
- •21.3 Use Stack Memory Carefully
- •21.5 Optimize Late
- •21.6 Summary
- •Glossary
- •Bibliography and Online Resources
- •Index
COMPATIBILITY AND THE SYMBIAN OS CLASS TYPES |
291 |
IMPORT_C virtual CSiamese(); public:
IMPORT_C virtual void EatL(); // Overrides base class functions
IMPORT_C virtual void SleepL();
// ...
};
//Function definitions not relevant to the discussion have been
//omitted
void CSiamese::EatL()
{// Overrides base class implementation
... // Omitted for clarity
}
void CSiamese::SleepL()
{// Calls base class implementation CCat::SleepL();
}
Provide ”Spare” Member Data and Virtual Functions
As you’ll have gathered from a number of the guidelines above, the use of virtual functions, although powerful in a C++ sense, can be quite limited in terms of extensibility when compatibility must be maintained. If it is possible that your class may need to be extended (and this is often hard to determine, so you may prefer to assume that it will), then you should add at least one reserve exported virtual function. This will give you the means by which to extend the class without disrupting the vtable layout of classes which derive from the class. In effect, this provides a means to get around the limits by which virtual functions may be extended, through the use of explicit interface design. You should, as always, implement any reserved functions, defaulting them to perform no action.
By the same token, you may wish to reserve at least four extra bytes of private member data in classes which may later need to be extended. This reserved data can be used as a pointer to extra data as it is required. Of course, if the class is internal to your component, or is unlikely to require later modification, you should not reserve extra memory in the class object, in order to continue to minimize the use of limited memory resources.
18.7 Compatibility and the Symbian OS Class Types
Chapter 1 describes the main class types, and their characteristics, on Symbian OS. The discussion in this chapter has mainly focused on compatibility issues which apply to C class objects and, to a lesser extent, R classes. T classes, by their very nature, tend to be stack-based and are often simple, taking a similar role to a C struct. T classes frequently
292 |
COMPATIBILITY |
do not have constructors and never have destructors. Once a T class is publicly defined, it is often difficult to make client-compatible changes to it.
18.8Summary
A change is acceptable if every line of code affected by it can be altered, where necessary, and the code rebuilt against the changes. In effect, this often means that a change must be restricted to the internals of a component rather than its public API. For this reason, you should endeavor to keep private definitions and header files (and anything else which is likely to be subject to change) out of the public domain.
A change is also acceptable if it can be verified as compatible, according to the guidelines I’ve discussed here. In general, the key compatibility issue for shared library DLLs is backward binary compatibility, with source compatibility an additional aim.
These guidelines derive from those used within Symbian, in accordance with the C++ standard. I am very grateful to David Batchelor, John Forrest and Andrew Thoelke of Symbian who have previously written guides to compatibility best practice on Symbian OS, which I used as the basis of this chapter.