From: Ulrich E. <ul...@do...> - 2002-06-15 23:59:31
|
On Saturday 15 June 2002 18:07, you wrote: > TABS & SPACES: > -------------- > Always use tabs instead of spaces. Tabs are always better. > It's not important how long tabs are. Use your editors defaults. > Spaces are the only way to guarantee that things appear the same on all editors. Imagine this: int myfunc( int arg1, int arg2, int arg3, int arg4, [tab] [tab] int arg5, int arg6, int arg7); It will be rendered differently depending on the size of a tab. > VARIABLE NAMING: > FUNCTION NAMING: > ARGUMENT NAMING: see Miguel's comments on this. Additionally, I'd like to say that the bigger the scope of an identifier, the more descriptive should be the name. Example: for( int i=0; ...) or int g_MaxAllowedConnections; > int My_Dummy_Function ( int player_number ) int MyDummyFunction( Object::ID player); > > BRACES USAGE: > ------------- > Use them always. not always. There is nothing unclear about if(!precondition) return false; > > SPACES BETWEEN TOKENS: > To make source code more readable, use spaces between tokens. > Here is example wrong and correct usage > > if ((i<3)&&(j>9)) (wrong) > if ( (i < 3) && (j > 9) ) (correct) if((i<3) && (j>9)) (my way) > FUNCTION COMMENTS: [snip] I tend to disagree a bit with this. First, you need to make a distinction between the interface and the implementation. The comments for the interface are always in the header and they describe 'what' it does/is/has. The other part is in the source-file and describes 'how' it is done. Example.h: /* example class This class is used during a mail-discussion about coding standards. Note: you can't derive from this because it doesn't have a virtual dtor. TODO: write the rest of the functions to make this useful */ class Object { public: enum Type { none = 0, // invalid type active, passive, }; /* unique identifier. Zero is reserved to mark invalid IDs */ typedef Uint32 ID; private: // not copyable Object(Object const&); // not assignable Object& operator=(); public: /** create an Object of the given type and assign it a new ID */ Object(Type type = none); /** create an object of the given type and ID */ Object(Type type, ID ); ~Object(); // convenience-typedef typedef std::list<Object> ObjList; /** retrieve a list of all Objects that are directly or indirectly attached to or contained in this one */ ObjList GetContent() const; private: Type m_type; ID m_id; ObjList m_slots; /** create a new ID */ static ID make_id(); } Example.cpp: Object::ObjList Object::GetContent() const { ObjList result; /* we iterate over all slots and recursively call GetContent for other container-objects */ for(ObjList::const_iterator it = m_slots.begin(); it!=m_slots.end(); ++it) { result += *it; if(it->isContainer()) result.splice(it->GetContent()); } return result; } Other notes about this example: - use a class-layout like this: 1. required typedefs or enums that are used by ctors 2. ctors, dtor, assignment operator. All that should not be used are declared in the private section but not implemented. 3. public functions 4. protected functions (if any) 5. private functions and data - use typedefs to reduce typing - use nested types to clearly mark the range where they are used - don't comment the obvious. I agree that it is hard to decide what is obvious, but commenting that 'result' will hold the return-value is clearly too much. Assume that the reader knows C++. - use empty lines to separate distinct entities from each other - objects that are just a conglomeration of data should be structs. Their data can be public and then should not be prefixed with 'm_'. Example: struct Point { float x; float y; }; |