OOFILE | Downloads | Purchasing | Press | Services | Company Information | Soapbox | References | F.A.Q. | HOME

OOFILE CONVENTIONS

NOTE ON IMPLEMENTATION TECHNIQUES

I have steered away from using templates and nested classes despite there being a few places where normal c++ practice would mandate their use. This is to avoid problems with compilers that lack or poorly implement these features.

Whilst in 2004, templates are well-implemented by mainstream compilers, the core OOFILE will continue to follow this minimalist constraint. Outer layers and add-on products may use templates.

CONVENTIONS

internal classes are prefixed by OOF_

external classes are prefixed by db

static members start with an 's' followed by an uppercase letter

all other members start with an 'm' followed by an uppercase letter

constants start with 'k' followed by an uppercase letter

local variables start with a lowercase word

parameters in header files are only named where the name adds to the readability
eg: dbQuery(dbQuery&) - not needed in copy constructor
dbfieldSeg(dbField&, unsigned int len) - len is needed

public functions start with a lowercase letter, private & protected functions start with an Uppercase

User database CONVENTIONS
dbField members start with an uppercase letter, eg dbChar LastName;

DYNAMIC MEMORY

Where a dynamically allocated member is "owned" by a class, meaning the class is responsible for it's allocation & deallocation, the member has
// owned
next to its declaration.

There are rare cases where a method transfers ownership of a member, or exposes a pointer. The names of these methods will have "adopt" or "expose" in them, or in a comment next to the name (eg: an operator char*).

Any time you see a pointer parameter which has "adopted" in the name it means you are no longer responsible for deleting that pointer.

Similarly, when a parameter or method has "orphan" in the name it means you are being returned a pointer for which your code is now responsible to delete.

There are a lot of pointer members in OOFILE which are purely references to related classes. Marking relevant pointers with //owned makes it easy to see which ones should be cleaned up in destructors.


CONCEPTS and IDIOMS

This section tries to summarise some of the c++ techniques I've used. I urge you to purchase Effective C++ but the following may help if you are fairly new to C++ and a little confused by some of OOFILE's code.

PROTECTED STATIC MEMBERS INSTEAD OF GLOBAL VARIABLES

In any library for general re-use, globals have the potential to cause conflicts and "pollute the namespace". They also suffer from uncontrolled access - anyone can fiddle with them. I use Static Class Members instead, which are global variables belonging to a specific class (eg: dbConnect::currentlyConstructing). They have to be explicitly qualified by the class name and you can restrict who has access using either Friend Classes or Friend Functions.

HANDLE CLASSES and REFERENCE COUNTING

OOFILE_Dictionary and OOFILE_DictRep form a pair, where the outer class forwards nearly all its function to the inner (except for iteration).

This allows multiple copies of OOFILE_Dictionary to point to a single copy of the actual data, in OOFILE_DictRep, at the cost of some extra forwarding logic. Note that any copy constructors or assignments that create a new OOFILE_Dictionary must update the reference count of the DictRep.

The forwarding is not as onerous as it may appear - use of inlines reduces it to little more than one pointer derefence over the normal use of virtual object.

(LAZY) SELF-EXPANDING ARRAYS, INDEXING and C++ OPERATOR OVERLOADING

I've overloaded operator[] (the array index) in three ways for the OOFILE_Dictionary. Notice that I've provided both unsigned int and signed int, as well as the named access.

There is a minor problem in providing a native unsigned int, without a signed int version, in that the literal constant 0 is typed as a signed int. By the c++ conversion rules, the literal constant 0 is one trivial conversion away from either a null pointer to char, or an unsigned int.

Thus, the ambiguity cannot be resolved. Providing an operator[] with a signed int (inlined for performance), gives an operator that can be called with no trivial conversions. Being a slightly better choice, therefore the compiler is happy that literal 0 will invoke the [signed int] version.

I've made OOFILE_DictRep a "lazy" array in that the default constructor doesn't declare any space and there is no requirement for users of the class to explicitly tell it to expand. If you look into the operator[] you'll notice it performs a range check and does an expansion. The expansion provides a null pointer in the target cell, so use of an out of range value on the rhs is legal and detectable:
myField = mFields[outOfRangeIndex];
if (myField)...

Feature index

(c) Copyright A.D. Software 1994-2004 (All Rights Reserved).
Last Updated: 21st June 2004