Books
in black and white
Main menu
Share a book About us Home
Books
Biology Business Chemistry Computers Culture Economics Fiction Games Guide History Management Mathematical Medicine Mental Fitnes Physics Psychology Scince Sport Technics
Ads

Symbian os Expleined effective C++ programming for smartphones - Batchelor D.

Batchelor D. Symbian os Expleined effective C++ programming for smartphones - Wiley publishing , 2005. - 394 p.
ISBN 0-470-02130-6
Download (direct link): symbianosexpltivec++2005.pdf
Previous << 1 .. 123 124 125 126 127 128 < 129 > 130 131 132 133 134 135 .. 151 >> Next

All else being equal, a reference can be more efficient than a pointer when the compiler must maintain a NULL pointer through a conversion. Consider the following class and pseudo-code:
class CSoupDragon : public CBase, public MDragon {...};
CSoupDragon* soupDragon;
MDragon* dragon;
dragon = soupDragon; // soupDragon may be NULL
For the conversion between CSoupDragon and MDragon, the compiler must add sizeof(CBase) to the soupDragon pointer in all cases, except where soupDragon is NULL, whereupon it must continue to be NULL rather than point incorrectly at the address which is the equivalent of sizeof(CBase). Thus the compiler must effect the following:
dragon = (MDragon*)(soupDragon ? (TUint8*)soupDragon+sizeof(CBase) :
NULL);
For a conversion which involves references rather than pointers, the test is unnecessary, since a reference must always refer to an object.
For any of your code that receives a pointer return value, or if you implement methods that take pointer parameters, you should consider the implications of receiving a NULL pointer. If an uninitialized value is incorrect, i.e. a programming error, you should use an assertion statement to verify that it is valid. The use of assertions for "defensive" programming is discussed further in Chapter 16.
MEMBER DATA AND FUNCTIONAL ABSTRACTION
309
20.4 Member Data and Functional Abstraction
In this discussion on the API of your class, I've discussed the definition of the member functions of your class, but not really touched on the member data. There's a very simple rule, which is that you should not make class data public, and there's a good reason for this - encapsulation.
The benefit of keeping your member data private to the class is that you can control access to it. First, you can decide whether to expose the data at all; if you choose to do so, you can provide member functions in your class to expose the data. If you follow the guidelines above, you can control precisely the type of access allowed. If you return const references, const pointers or a value, the caller has read-only access, while returning a reference or a pointer allows the caller to modify the data, as illustrated by the following:
const TExamplek ReadOnlyReference(); const TExample* ReadOnlyPointer();
TExample ReadOnlyValue();
TExamplek ReadWriteReference();
TExample* ReadWritePointer();
An additional benefit of keeping class member data private is a degree of functional abstraction. By providing methods to Set() and Get(), the variable is not exposed directly. Should you later decide to change the implementation of the class, you can do so without requiring your clients to update their code.
For example, consider this rather contrived class which stores a password and compares it with a password typed in later, providing a re-usable class for applications to protect their user files. In version 1.0, the unencrypted password is, rather naively, stored within the object. The code is released and everyone is happy for a while, including a few hackers. A code review before version 2.0 highlights the problem. If the class has been declared as follows, any attempt to add more security to the class forces clients of the class to change their code. Incidentally, I discuss how to maintain compatibility for client code in Chapter 18.
// Version 1.0
class CPassword : public CBase {
public:
... // Other functions omitted for clarity public:
// Bad! There are no access functions - the member data is public // The caller can set and get the password directly HBufC8* iPassword;
};
310
EXPOSE A COMPREHENSIVE AND COMPREHENSIBLE API
The same problem arises in a second definition (version 1.1) below, but for different reasons. This class is a step in the right direction, because the password data is at least private. To set and get the password, the caller must call a method explicitly rather than modify the contents of the object directly.
// Version 1.1
class CPassword : public CBase {
public:
IMPORT_C void SetPasswordL(const TDesC8& aPassword); inline HBufC8* Password(); // Better! But not great private:
HBufC8* iPassword; // Better. Password is private };
inline HBufC8* CPassword::Password()
{
return (iPassword);
}
// SetPasswordL() is a leaving method because allocation // of iPassword may leave if there is insufficient memory EXPORT_C void CPassword::SetPasswordL(const TDesC8& aPassword)
{
HBufC8* newPassword = aPassword.AllocL(); delete iPassword; iPassword = newPassword;
}
To access the data, the caller must now call Password(), which provides read/write access to iPassword. Sure, it returns a constant heap descriptor, but from Chapters 5 and 6, you know how to call Des() on that pointer to get a modifiable pointer which can be used to update the contents of the buffer. This is far from ideal; the password should only be modifiable through the SetPasswordL() method, otherwise it's confusing for the client to know which to use. To get read-only access, the method should either return a const HBufC8* or, preferably, return a constant reference to the more generic descriptor type, TDesC8, as follows:
Previous << 1 .. 123 124 125 126 127 128 < 129 > 130 131 132 133 134 135 .. 151 >> Next