To be sure what the proper normalization is, read the {{path|.moc}} file

+

generated for the class.

'''Note''': If you are unsure about the normalization, don't do it. Let

'''Note''': If you are unsure about the normalization, don't do it. Let

Revision as of 13:22, 15 January 2009

This document describes some of the recommended conventions that should be applied in the KDE libraries (not applications). Respecting these guidelines helps create a consistant API and also may help ease maintainence of the libraries later. While these conventions are not mandatory, they are important guidelines, and should be respected unless you have a good reason to disregard them.

Naming Conventions

Class names starts with a capital K. The rest is in camel case. Function names starts with a lower case, but the first letter of each successive word is capitalized.

Unless dealing with central libraries (kdecore, kdeui), classes should be in the library namespace. In that case, it is the namespace which starts with K and the classes inside may not start with it. New libraries should choose their namespace.

The prefix 'set' is used for setters, but the prefix 'get' is not used for accessors. Accessors are simply named with the name of the property they access. The exception is for accessors of a boolean which may start with the prefix 'is'.

Sometimes, complex code may be moved to a member method of the Private class itself. Doing this may give the compiler an extra register to optimize the code, since you won't be using "d" all the time. Also, remember to inline such methods if they are called only from one place.

Shared D-Pointers

If your class hierarchy is large and/or deep, you may want to try the concept of shared d-pointers. You'll be trading the added complexity for a smaller memory footprint in the main object (there will be only one "d" variable in it). Other advantages include:

direct access to the private data of the whole hierarchy (in other words, the Private classes are in fact "protected", not "private")

access to the parent's d-pointer methods

The latter advantage is especially useful if your class has moved the code from the main class to the Private class. If that's the case, you should be calling the Private methods instead: since they are not exported, they will create simpler relocations in the final library (or none at all). By simply calling the Private method instead of the public one, you contribute to a faster load-time of your library.

To implement a "shared d-pointer", you need to:

define a protected variable (d_ptr) in the least derived class of your hierarchy

in each class of the hierarchy, define a private function called d_func() that reinterpret_casts that d_ptr to the current class's Private class

use Q_D(Foo) at the beginning of the functions to have access to a variable "d"

the private classes derive from one another just like the public hierarchy; they also have virtual destructors

add one extra, protected constructor that takes the private class as a parameter

in each constructor for all derived classes, call the parent's constructor that takes the d pointer as a parameter

Q_DECLARE_PRIVATE

This is a handy macro that hides the ugly stuff for you. It creates the d_func() function for you, using the variable called d_ptr. If yours has that name, you can use this macro. If it has another name, maybe you should create a macro to make your code look nicer.

Q-Pointers

Q-pointers are like d-pointers, but work in the reverse direction: they are in the Private class and they point to the public class. Needless to say, this is only possible for classes that don't share their d-pointers. Examples of classes that might benefit from q-pointers are all those derived from QObject, while classes with implicit sharing are those that potentially can't use it.

Q-pointers are especially useful if your class has moved most of the code to the Private class as recommended. In that case, you may need to emit signals from the Private class. You would do it as:

emit q->signalName();

(You need to declare the Private class a friend of your public one; Q_DECLARE_PRIVATE does that for you)

Q-pointers may also use the a shared q-pointer technique just like d-pointers can. What's more, Qt also provides a macro called Q_DECLARE_PUBLIC and one Q_Q to hide the ugly parts of the implementation.

Inline Code

Installed headers should compile with the following preprocessor defines: QT_NO_CAST_FROM_ASCII, QT_NO_CAST_TO_ASCII, QT_NO_KEYWORD. So don't forget QLatin1String.

No C casts in the header. Use static_cast if types are known. Use qobject_cast instead of dynamic_cast if types are QObject based. dynamic_cast is not only slower, but is also unreliable across shared libraries.

Flags

Because when you read code that uses the above function, you can't easily know the significance of the parameters

window->setCaption(KApplication::makeStdCaption( "Document Foo",

true, true));

The solution is to use QFlags. If the options only apply to one function, call the enum FunctionNameOption and the QFlags typedef FunctionNameOptions. Do that even if there is only one option, this will allow you to add more options later and keep the binary compatibility.

Const References

Each object parameter that is not a basic type (int, float, bool, enum, or pointers) should be passed by reference-to-const. This is faster, because it is not required to do a copy of the object. Do that even for object that are already implicitly shared, like QString:

QString myMethod( const QString& foo,

const QPixmap& bar,
int number );

Note: Avoid const references for return types though. Returning for example
const QList<int> &someProperty() const;
means exposing the internal data structure for someProperty() and it's very difficult to change it in the future while preserving binary compatibility. Especially for implicitly shared objects the one refcount that one avoids by returning a const reference is often not worth it the exposure of implementation.

There are cases where it makes sense, where performance is absolutely critical and the implementation is very fixed. So think twice about it and consider returning a value instead:
QList<int> someProperty() const;

Signals and Slots

In the libraries, use Q_SIGNALS and Q_SLOTS instead of signals and slots. They are syntactically equivalent and should be used to avoid conflicts with boost signals, and with python's use of "slots" in its headers.

Properties

Consider using Q_PROPERTY for properties. The reason is that properties (especially those marked SCRIPTABLE) will be accessible through the javascript interface.

If you follow the propname / setPropname naming scheme, moc sets a special flag for the QMetaProperty.

Explicit Constructors

For each constructor (other than the copy constructor), check if you should make the constructor explicit in order to minimize wrong use of the constructor.

Basically, each constructor that may take only one argument should be marked explicit unless the whole point of the constructor is to allow implicit casting.

Avoid including other headers in headers

Try to reduce as much as possible the number of includes in header files. This will generally help reduce the compilation time, especially for developers when just one header has been modified. It may also avoid errors that can be caused by conflicts between headers.

If an object in the class is only used by pointer or by reference, it is not required to include the header for that object. Instead, just add a forward declaration before the class.

In this example, the class KFoo uses KBar by reference, so we do not need to include KBar's header:

include <kfoobase.h>

class KBar;
class KFoo : public KFooBase
{

public:
/* [...] */
void myMethod(const KBar& bar);

};

Getting #includes right

There are two types of #include statements: #include <foo.h> and #include "foo.h".

Say we have the file xyz.h in /usr/include/mylib/ that contains the following:

include <header1.h>

include "header2.h"

The preprocessor will search for the file header1.h in all the paths given as -I arguments and then replace the line with the contents of that file.

For line 2 the preprocessor tries to use the file /usr/include/mylib/header2.h first and if it does not exist search for the file like it did for header1.h. The important part to note here is that the preprocessor does not look in the directory of the source file that includes xyz.h but in the directory where xyz.h resides.

Now, which include statement is the one to use? After all you can specify every directory you want using -I (or rather CMake's include_directories()) and thus could use #include <...> everywhere.

As application developer

Include headers from external libraries using angle brackets.

include <iostream>

include <QtCore/QDate>

include <zlib.h>

Include headers from your own project using double quotes.

include "myclass.h"

Rationale: The header files of external libraries are obviously not in the same directory as your source files. So you need to use angle brackets.

Headers of your own application have a defined relative location to the source files of your application. Using KDE4's cmake macros your source directory is the first include switch to the compiler and therefore there's no difference in using angle brackets or double quotes. If you work with a different buildsystem that does not include the current source directory or disable CMAKE_INCLUDE_CURRENT_DIR then all includes (inside your application) using angle brackets will break.

Ideally the buildsystem would not need to specify -I

Invalid language.

You need to specify a language like this: <source lang="html4strict">...</source>