The K Desktop Environment

Next Previous Table of Contents

15. Programming Guidelines

Close to the end of this handbook, I want to summarize several issues that programmers should watch out while coding. These are mostly C++ programming tips that relate to KDE and Qt programming especially and are partly taken from the KDE Developer's Center which can be found on the Internet at http://www.kde.org, some have been added by my own experience.

15.1 General Rules

Filenames

First of all, when creating sourcefiles, you should always use lowercase filenames. KDevelop supports this guideline already if you stick to its filename aut-suggestion. This makes it easier for other developers to remember what source files to look for when they have to debug your application.

Classnames

The classnaming for KDE projects is recommended to be:

  • class names should begin with a prefixed K followed by the name of the class by purpose (your choice). This would be e.g. KMyWidget for an application specific widget.
  • the class members should always begin with lowercase letters, followed by uppercase beginnings for the next word, e.g. myWidgetPointer()
  • methods that return a private members value shouldn't use the get-prefix. You should prefer using a descriptive name for those types of classmembers. Example: b_myboolean is a private member. The method returning the current value would be e.g. myBoolean().

File access within code

Hardcoding any path should be avoided by using the KDE File System Standard. You only have to watch the installation path for your files by the according macros of the Makefile.am as described in this handbook. Within the code, you should use the methods of KApplication to retrieve the actual path.

Class documentation

Another thing already mentionend is class documentation. You should stick to use KDoc formatting rules as they are used by all KDE developers to document their classes. You should at least add a single line to all of your classmembers for yourself to remember the prurpose and for others to reuse code. The code-reuse by the GPL makes much more sense if you know where to find an already existing solution if classes are documented. The Qt library referece is a good example of well-documented interfaces, though it doesn't use KDoc.

Use new to create widgets

Within your implementation, you should always prefer to create widgets on the heap with new. The Qt library has a nice habbit to automatically delete all child widgets you created with new, so you don't ever have to use delete again in those cases. This is one of the most important practical features of the Qt library and you should make wide use of this.

Debugging

When it comes to debugging, you should make use of the macros KDebug provides. Those are similar to the Qt macros, but can be retrieved by the keycode STRG+ALT+F12. See the KDE Library Reference Guide for more information about the event filtering of these Macros. You could as well use assert(), but should try to be consistent with your debugging code.

const-declarations

Further, you should use const declarations for member functions that should or do not change any private member. This would be the case for all methods that only return the current value of a private member. This avoids changing the value accidently and will catch those logical errors at compile time. Now, towards initializing const members you should stick to do that together with using static in the declaration and initialize the value outside the constructor like this:

class foo {
        static const int value;
};

const foo::value = 10;
ANSI C++ allows to initialize the member inside the constructor but you should avoid this as a few compilers are not capable of this feature.

Virtual methods

As explained in section User Interaction, you should stick to the access rights and the declaration by virtual when overwriting virtual methods. At least you shouldn't reduce the access of a virtual method from protected to private.

Forward declarations

Class-headers should be included where you dereference any object or instance of a class in your sourcecode. That means if your class uses a member of another class, replace the #include directive with a forward declaration of the class, e.g instead of:

#include <qpushbutton.h>

class KMyWidget:public QWidget
{

private:
  QPushButton* ok_button;
};

you should prefer to only declaring the class QPushButton in the header file:

class QPushButton;

class KMyWidget:public QWidget
{

private:
  QPushButton* ok_button;
};

and place the include directive into the according sourcefile where e.g. the instance ok_button is dereferenced with any method of the class QPushButton. This saves compile time at any rate, especially if you're using instances of classes that your're working on. The compiler will recompile all souces that include the header file if you made any changes on the interface of the class, therefore a simple addition of a method that only returns an internal value will lead to a recompilation of all sources tha include the header file of the class.

Unused Parmeter Warnings and default arguments

Also you should leave out formal parameters of methods that don't necessarily require the actual parameter to work. This avoids the unused parameter warnings of your compiler when he sees a method that retrieves a formal parameter but doesn't use it in its implementation. Usually, you will set some default arguments for several methods. Those should always be placed in the declaration of the class member instead of setting them in the member implementation.

Using config.h

KDevelop projects as well as any other project that is using autoconf to create a configure-script produce a file config.h after executing the configure-script on the target machine. The values found by configure are listed there and can be used within the sourcecode. The directive to include the config.h file is:

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

One of the most recently used entries of config.h is probably the type-definition of bool for compilers that don't comply with the newest ANSI C++ draft.

Use 0 instead of NULL

You should stickt to using 0 directly instead of NULL for preset values like the Qt and KDE libraries already do. This increases portablility of your applications towards different compilers that have problems with NULL.

Temporaries

You should declare temporary instances always before using them. This is generally considered better than direct use. Example:

// Don't:
for( int i=0; i<n; i++){
  //do something
  };

// Do:
int i;

for(i=0; i<n; i++){
  //do something
  };

This also counts on using temporaries in function calls:

// Don't:
setColor( &(QColor(black)) );

// Do:
QColor color(black);
setColor( &color );

15.2 Operating System Dependencies

As KDevelop projects use the GNU tools to create projects, it is ensured that your application will run on almost every Unix system. However, you may encounter problems when actually compiling your application under another Unix, because header files are located somewhere different or you need another implementation especially when it comes to using OS-specific low-level functions which can differ from system to system.

When programming with C++ and Qt/KDE you should also notice that the Qt collection classes have a rich set of functionality that is already compiler/OS independend and makes things much easier, starting with strings (QString) to file reading/writing (QFile); so using Qt will make using OS defines almost obsolete in most cases.

Anyway, when using Qt and you still have to use #defines for your application, you should include qglobal.h and make use of the already predefined defines for various Operating Systems and compilers which preselects the below defines already.

Instead of letting the packagers of OS-Vendors applying any patches to your application (like most do where necessary e.g. for building rpmīs or packages/ports), you should use defines for those sections that are operating-system specific (but you donīt have to use -D for compiling, the Operating System defines are handled automatically). The following lists the available systems and their defines (additional defines in brackets):

AIX:

#ifdef _AIX

BSDI Unix:

#if defined(bsdi) || defined(__bsdi__)

Dec Ultrix:

#if defined (ultrix) || defined(__ultrix) || defined(__ultrix__)

DG Unix:

#if defined(DGUX)

FreeBSD:

#ifdef __FreeBSD__

GNU Hurd:

#if defined(__GNU__)

HP-UX:

#if defined (hpux) || defined (__hpux) || defined (__hpux__)

Linux:

#if defined(linux) || defined(__linux) || defined(__linux__)

NetBSD:

#ifdef __NetBSD__

OpenBSD:

#ifdef __OpenBSD__

OSF Unix:

#if defined(__osf__)

QNX:

#if defined(__QNX__)

SCO UnixWare:

#if defined(_UNIXWARE)

SCO UnixWare 7:

#if defined(sco) || defined(_UNIXWARE7)

SCO:

#if defined(_SCO_DS) || defined(M_UNIX) || defined(M_XENIX)

SGI Irix:

#if defined(sgi) || defined(__sgi)

SunOS:

#if defined (sun) || defined (__sun) || defined (__sun__)

Sun Solaris:

#if defined (_OS_SUN_) || defined (__SVR4)

Next Previous Table of Contents