X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/51ab94007251bbad56b82e5509c72a7b0e7ec13c..5acf8f1d43fb8544971f205989b8e01cd91d0ce3:/docs/html/standard.htm diff --git a/docs/html/standard.htm b/docs/html/standard.htm deleted file mode 100644 index 196b63ff5a..0000000000 --- a/docs/html/standard.htm +++ /dev/null @@ -1,953 +0,0 @@ - -
-- -wxWindows Programmer Style Guide - - | -
- -by Vadim Zeitlin
- -This guide is intended for people who are (or intending to start) writing code -for wxWindows class library. - -
-The guide is separated into two parts: the first one addresses the general -compatibility issues and is not wxWindows-specific. The advises in this part -will hopefully help you to write programs which compile and run on greater -variety of platforms. The second part details the wxWindows code organization and -its goal it to make wxWindows as uniform as possible without imposing too -many restrictions on the programmer. -
-Acknowledgements: This guide is partly based on -C++ portability guide by David Williams. - -
-
- -
The usage of all features in this section is not recommended for one reason: they appeared in C++ relatively recently and are not yet -supported by all compilers. Moreover, when they're supported, there are -differences between different vendor's implementations. It's understandable that -you might love one (or all) of these features, but you surely can write C++ -programs without them. Where possible, workarounds to compensate for absence -of your favourite C++ abilities are indicated. -
Just to suppress any doubts that there are compilers which don't support -these new features, you can think about Win16 (a.k.a. Win 3.1) compilers, -none of which supports any feature from the list below. - -
-Besides the reasons mentioned above, template usage also makes the -program compile much slower (200%-300% is not uncommon) and their support -even in the compilers which have had it for a long time is far from perfect -(the best example is probably gcc). -
Workaround: The things you would like to use templates for are, -most commonly, polymorphic containers (in the sense that they can contain objects of -any type without compromising C++ type system, i.e. using void * -is out of question). wxWindows provides dynamic -arrays and lists which are sufficient in 99% of cases - please don't hesitate -to use them. Lack of template is not a reason to use static arrays or -type-less (passing by void *) containers. - -
-The C++ exception system is an error-reporting mechanism. Another reasons not to use it, -besides portability, are the performance penalty it imposes (small, but, at least for -current compilers, non-zero), and subtle problems with -memory/resource deallocation it may create (the place where you'd like to use -C++ exceptions most of all are the constructors, but you need to be very -careful in order to be able to do it). -
Workaround: there is no real workaround, of course, or the exceptions -wouldn't have been added to the language. However, there are several rules which -might help here:
- -
There is no such thing as a function that never fails - even if it can't - fail now, it might do it later, when modified to be more powerful/general. - Put the int or bool return type from the very beginning!
-
Never rely on the function's success, always test for a possible error.
-
Exceptions are always caught and, normally, processed when they're - caught. In the same manner, the error return code must always be processed - somehow. You may choose to ignore it, but at least tell the user that - something wrong happened using wxLogError or - wxLogWarning functions. All wxWindows - functions (must) log the error messages on failure - this can be disabled - by using wxLogNull object before calling it. -
Examples:
-void ReadAddressBookFile(const wxString& strName) -{ - wxFile file; - - if ( !file.Open(strFile) ) - return; - - ...process it... -} --
-// returns false if the address book couldn't be read -bool ReadAddressBookFile(const wxString& strName) -{ - wxFile file; - - if ( !file.Open(strFile) ) { - // wxFile logged an error because file couldn't be opened which - // contains the system error code, however it doesn't know what - // this file is for and an error message "can't open $GLCW.ADB" - // can be quite confusing for the user. Here we say what we mean. - wxLogError("Can't read address book from '%s'!", - strName.c_str()); - return false; - } - - ...process it... - - return true; -} -- or, if it's not an error if file doesn't exist (here we could just check - its existence, but let's suppose that there is no wxFile::Exists()) - we can also write: -
-// returns false if address book file doesn't exist -bool ReadAddressBookFile(const wxString& strName) -{ - wxFile file; - - // start a block inside which all log messages are suppressed - { - wxLogNull noLog; - if ( !file.Open(strFile) ) - return false; - } - - ...process it... - - return true; -} -
-RTTI stands for Run-Time Type Information and there is probably no other -reason not to use it except the portability issue and the fact that it adds -sizeof(void *) bytes to any class having virtual functions (at least, -in the implementations I'm aware of). -
Workaround: use wxWindows RTTI system which allows you to do almost -everything which the new C++ RTTI, except that, of course, you have to use -macros instead of the (horrible looking, BTW) dynamic_cast. - -
-This topic is subject to change with time, however for the moment all wxWindows -classes/functions live in the global namespace. -
Workaround: None. - -
-STL is the new C++ standard library, proposing all kinds of template containers -and generic algorithm implementations. Templates are the heart (and almost -everything else) of the library, so its usage is out of question. Besides, even -with the compilers which do support templates, STL has many of its own problems, -there are many "not 100% standard compatible" vendor implementations, none of existing debuggers understands its -complicated data structures, ... the list can go on (almost) forever. -
Workaround: Use wxString, dynamic arrays and lists and other wxWindows -classes. wxString has many of the most often used functions of std::string STL -class (typedef to be precise). -
-The scope of a variable declared inside for() statement changed several -years ago, however many compilers still will complain about second declaration -of i in the following code: -
- for ( int i = 0; i < 10; i++ ) { - ... - } - - ... - - for ( int i = 0; i < 10; i++ ) { - ... - } --even though if it's perfectly legal now. -
Workaround: write this instead: -
- int i; - for ( i = 0; i < 10; i++ ) { - ... - } - - ... - - for ( i = 0; i < 10; i++ ) { - ... - } --or, even better, use different names for the variables in the different for -loops (in particular, avoid mute variable names like i above) - then -you can declare them in the loop statement and don't pollute the outer name -space with local loop variables. - -
-Nested classes are, without doubt, a very good thing because they allow to hide -"private" (in the sense that they're used only inside the library) classes and, -generally, put the related things together. -
Unfortunately, some compilers have trouble understanding them, so we must -sacrifice the ideals of software design to get a working program in this case. -
Workaround: instead of -
- // in the header - class PublicLibClass { - ... - private: - class PrivateLibClass { ... } m_object; - }; --you can try the following: -
- // in the header - class PrivateLibClass; // fwd decl - class PublicLibClass { - ... - private: - class PrivateLibClass *m_pObject; - }; - - // in the .cpp file - class PrivateLibClass { ... }; - - PublicLibClass::PublicLibClass() - { - m_pObject = new PrivateLibClass; - - ... - } - - PublicLibClass::~PublicLibClass() - { - delete m_pObject; - } --
A nice side effect is that you don't need to recompile all the files -including the header if you change the PrivateLibClass declaration (it's -an example of a more general interface/implementation separation idea). - -
-The C++ standard has introduced the following new reserved words: or, -and, not, xor, bitand, bitor, -compl, and_eq, or_eq, not_eq, -or_eq which can be used instead of the usual C operations &&, -||, ~ etc. -
This wonderful (and not backwards compatible in addition to being -absolutely useless) new feature means that these new keywords should not be -used as the variable names - even if current compilers usually will accept -this, your code will break in the future. For most of the keywords, using them -as variable names is quite unlikely, but or and compl were -used in the wxWindows sources which seems to indicate that they are the most -likely candidates. -
It goes without saying that these new keywords should not be used instead -of the tradional C operators neither both because most compilers don't accept -them and because using them in C code makes it less readable. -
-This section lists the less obvious limitations of the current C++ compilers -which are less restrictive than the ones mentioned in the previous section but -are may be even more dangerous as a program which compiles perfectly well on -some platform and seems to use only standard C++ featurs may still fail to -compile on another platform and/or with another compiler. - -
- The ternary operator ?: shouldn't be used with objects (i.e. if any -of its operands are objects) because some compilers (notably Borland C++) fail -to compile such code. -
Workaround: use if/else instead. -
- wxString s1, s2; - - // Borland C++ won't compile the line below - wxString s = s1.Len() < s2.Len() ? s1 : s2; - - // but any C++ compiler will compile this - wxString s; - if ( s1.Len() < s2.Len() ) - s = s1; - else - s = s2; -- -
-The initializers for automatic array variables are not supported by some older -compilers. For example, the following line -
- int daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; --will fail to compile with HP-UX C++ compiler. -
Workaround: either make the array static or initialize each item -separately: in the (stupid) example above, the array should be definitely -declared as static const (assuming that the leap years are dealt with -elsewhere somehow...) which is ok. When an array is really not const, you -should initialize each element separately. - -
-It is a good rule to follow in general, but some compilers (HP-UX) enforce it. -So even if you are sure that the default constructor for your class is ok but -it has a destructor, remember to add an empty default constructor to it. -
-While the recommendations in the previous section may not apply to you if you're -only working with perfect compilers which implement the very newest directives of -C++ standard, this section contains compiler- (and language-) independent advice -which must be followed if you wish to write correct, i.e. working, programs. It -also contains some C/C++ specific remarks in the end which are less -important. -
-Never use C++ comments in C code - not all C compilers/preprocessors -understand them. Although we're mainly concerned with C++ here, there are -several files in wxWindows sources tree which are compiled with C compiler. -Among them are include/wx/setup.h and include/wx/expr.h. - -Another thing related to C vs C++ preprocessor differences is that some old C -preprocessors require that all directives start in the first column (while -it's generally allowed to have any amount of whitespace before them in C++), -so you should start them in the beginning of the line in files which are -compiled with C compiler. - -
-In C++, the constructors of global variables are called before the -main() function (or WinMain() or any other program entry point) -starts executing. Thus, there is no possibility to initialize anything -before the constructor call. The order of construction is largely -implementation-defined, meaning that there is no guarantee that one global -object will be initialized before another one (except if they are both defined -in the same translation unit, i.e. .cpp file). Most importantly, no custom -memory allocation operators are installed at the moment of execution of global -variables constructors, so a (less restrictive) rule is that you should have -no global variables which allocate memory (or do anything else non-trivial) in -the constructor. Of course, if an object doesn't allocate memory in its constructor -right now, it may start making it later, so you can only be sure about this if -you don't use any variables of object (as opposed to simple: -int, ...) types. Example: currently, wxString doesn't allocate memory -in its default constructor, so you might think that having a global (initially) -empty wxString is safe. However, if wxString starts allocating some minimal -amount of memory in its default constructor (which doesn't look unreasonable), -you would have all kinds of problems with new -and delete operators (overloaded in wxWindows), especially because the first new called -is the standard one (before wxWindows overloads them) and delete will -be the overloaded operator. - -
-Give the compiler a chance to help you - turn on all warnings! You should always -use the maximum available warning level of your compiler and understand and -correct each of them. If, for whatever reasons, a compiler gives a warning on -some perfectly legal line of code and you can't change it, please insert a -comment indicating it in the code. Most oftenly, however, all compiler warnings -may be avoided (not suppressed!) with minimal changes to your code. - -
-You should never assume any absolute constraints on data type sizes. Currently, -we have 16-bit, 32-bit and 64-bit machines and even inside each class data type -sizes are different. A small table illustrates it quite well: -
Architecture/OS | -sizeof(short) | -sizeof(int) | -sizeof(long) | -sizeof(void *) | -
i386/Windows 3.1 | -2 | -2 | -4 | -2 or 4 | -
i386/Windows 95 | -2 | -4 | -4 | -4 | -
Merced/Win64 | -2 | -4 | -4 | -8 | -
Alpha/Linux | -??? | -??? | -??? | -??? | -
-Although close to the heart of many C programmers (I plead guilty), code like -classical if ( (c = getchar()) != EOF ) is bad because it prevents you -from enabling "assignment in conditional expression" warning (see also -above) which is helpful to detect common -mistypes like if ( x = 2 ) instead of if ( x == 2 ). - -
-If you have to temporarily disable some code, use -
- #if 0 // VZ: I think this code is unneeded, it probably must be removed - ... - #endif // 0 --instead of -
- /* - ... - */ --The reason is simple: if there are any /* ... */ comments inside -... the second version will, of course, miserably fail. - -
- -You should avoid having overloaded virtual methods in a base class because if -any of them is overriden in a derived class, then all others must be overriden -as well or it would be impossible to call them on an object of derived class. - -For example, the following code: - -
- class Base - { - public: - virtual void Read(wxFile& file); - virtual void Read(const wxString& filename); - }; - - class Derived : public Base - { - public: - virtual void Read(wxFile& file) { ... } - }; - - ... - - Derived d; - d.Read("some_filename"); // compile error here! -- -will fail to compile because the base class function taking filename -is hidden by the virtual function overriden in the derived class (this is -known as [virtual] function name hiding problem in C++). - -
-The standard solution to this problem in wxWindows (where we have such -situations quite often) is to make both Read() functions not virtual -and introduce a single virtual function DoRead(). Usually, it makes -sense because the function taking a filename is (again, usually) implemented -in terms of the function reading from a file anyhow (but making only this -functions not virtual won't solve the above problem!). -
-So, the above declarations should be written as: -
- class Base - { - public: - void Read(wxFile& file); - void Read(const wxString& filename); - - protected: - virtual void DoRead(wxFile& file); - }; - - class Derived : public Base - { - protected: - virtual void DoRead(wxFile& file) { ... } - }; -- -This technique is widely used in many of wxWindows classes - for example, -wxWindow has more than a dozen of DoXXX() functions which -allows to have many overloaded versions of commonly used methods such as -SetSize() - -
-Some compilers don't pay any attention to extra semicolons on top level, as in -
- class Foo { };; --while others complain loudly about it. Of course, you would rarely put 2 -semicolons yourself, but it may happen if you're using a macro -(IMPLEMENT_something, for example) which already has a ';' inside and -put another one after it. -
- Two operating systems supported by wxWindows right now are (different flavours -of) Unix and Windows 3.1/95/NT (although Mac, OS/2 and other ports exist/are -being developed as well). The main differences between them are summarized -here. - -
-There is, unfortunately, no standard exceptions for C++ source files. Different -people use .C, .cc, .cpp, .cxx, .c++ and probably several others I forgot. Some -compilers don't care about extension, but there are also other ones which can't -be made to compile any file with "wrong" extension. Such compilers are very -common in DOS/Windows land, that's why the .cpp extension is the least likely to -cause any problems - it's the standard one under DOS and will probably be -accepted by any Unix compiler as well (any counter examples?). The extension -for the header files is .h. - -
-Although it's too silly to mention, please don't use backslashes in -#include preprocessor statement. Even not all Windows compilers accept -it, without speaking about all other ones. - -
-This problem will hopefully not arise at all, with CVS taking care of this
-stuff, however it's perhaps not useless to remember that many Unix compilers
-(including, but not limited to, gcc) don't accept carriage returns
-(=
-DOS/Windows 3.1 isn't case sensitive, Windows 95/NT are case preserving, but not
-case sensitive. To avoid all kinds of problems with compiling under Unix (or
-any other fully case-sensitive OS), please use only lower case letters in the
-filenames.
-
-
-While DOS/Windows compilers don't seem to mind, their Unix counterparts don't
-like files without terminating new-line. Such files also give a warning message
-when loaded to vim (the Unix programmer's editor of choice :-)), so please think
-about terminating the last line.
-
-
-The linker on VMS is case-insensitive. Therefore all external variables and
-functions which differ only in case are not recognized by the linker as
-different, so all externals should differ in more than the case only:
-i.e. GetId is the same as GetID.
-
-
- All wxWindows specific style guidelines are specified in the next -section, here are the choices which are not completely arbitrary, -but have some deeper and not wxWindows-specific meaning. - -
-We all know how important it is to write readable code. One of the first steps -in this direction is the choice of naming convention. It may be quite vague or -strictly define the names of all the variables and function in the program, -however it surely must somehow allow the reader to distinguish between -variable and functions and local variables and member variables from the first -glance. -
The first requirement is commonly respected, but for some strange reasons, the -second isn't, even if it's much more important because, after all, the immediate -context usually allows you to distinguish a variable from a function in -C/C++ code. On the other hand, you cannot say what x in the -following code fragment is: -
- void Foo::Bar(int x_) - { - ... - - x = x_; - - ... - } --It might be either a local variable (unluckily the function is too long so you -don't see the variable declarations when you look at x = x_ line), a -member variable or a global variable - you have no way of knowing. -
The wxWindows naming convention gives you, the reader of the code, much more -information about x. In the code above you know that it's a local -variable because:
-
Examples: -
- extern int g_x; // of course, 'x' is not the best name for a global... - - void Bar() - { - int x; - } - - class Foo { - public: - void SetX(int x) { m_x = x; } - private: - int m_x; - }; --As you see, it also solves once and for all the old C++ programmer's question: -how to call SetX() parameter? The answer is simple: just call it -x because there is no ambiguity with Foo::m_x. -
The prefixes can be combined to give ms_ and gs_ for static -member (a.k.a. class) variables and static global variables. -
The convention is, of course, completely worthless if it is not followed: -nothing like being sure that x is a local variable in the code fragment -above and discovering later the following lines in the header: -
- class Foo { - ... - int x; // I don't like wxWindows naming convention - }; --Please do use these prefixes, they make your code much easier to read. Also -please notice that it has nothing to do with the so-called Hungarian notation -which is used in wxMSW part of wxWindows code and which encodes the type -of the variable in its name - it is actually quite useful in C, but has little -or no sense in C++. - -
-In ANSI C, void Foo() takes an arbitrary number of arbitrarily typed -arguments (although the form void Foo(...) is preferred) and void -Foo(void) doesn't take any arguments. In C++, however, the situation is -different and both declarations are completely equivalent. As there is no need -to write void in this situation, let's not write it - it can only be -confusing and create an impression that it really means something when it's not -at all the case. - -
-In both C and C++ an argument passed by value cannot be modified - or, more -precisely, if it is modified in the called function, only the local copy is -really changed, not the caller's variable. So, semantically speaking, there is -no difference between void Foo(int) and void Foo(const int). -However, the const keyword is confusing here, adds nothing to the code -and even cannot be removed if Foo() is virtual and overridden (because -the names are mangled differently). So, for arguments passed by value -you shouldn't use const. -
Of course, it doesn't apply to functions such as -void PrintMessage(const char *text) where const is mandatory. -
- -
-
-The wxWindows files for each supported platform have their own subdirectories -in "include" and "src". So, for example, there is "src/msw", "include/gtk" -etc. There are also two special subdirectories called "common" and -"generic". The common subdirectory contains the files which are platform -independent (wxObject, wxString, ...) and the generic one the generic -implementations of GUI widgets, i.e. those which use only other wxWindows -classes to implement them. For the platforms where the given functionality -cannot be implemented natively, the generic implementation is used and the native -one is used for the others. As I feel that it becomes a bit too confusing, -here is an example: wxMessageBox function is implemented natively under -Windows (where it just calls MessageBox API), but there is also a generic -implementation which is used under, for example, GTK. A generic class should -normally have a name that distinguishes it from any platform-specific implementation. -A #define will allow wxGenericMessageDialog to be wxMessageDialog on some -platforms, for example. - -
This scheme applies not only for the .cpp files, but also for the headers. -However, as the program using wxWindows should (ideally) not use any -"#ifdef <platform>" at all, the headers are always included with -"#include <wx/msgdlg.h>" (for example). This file, in turn, includes -the right header for given platform. Any new headers should conform to this -setup as well to allow including <wx/foo.h> on any platform.
- -Note that wxWindows implementation files should use quotes when including wxWindows -headers, not angled brackets. Applications should use angled brackets. This -ensures that the dependencies are correctly handled by the compiler. - -
-To minimize the compile time C++ programmers often use so called include -guards: for example, in the header file foo.h you might have - -
-#ifndef _FOO_H_ -#define _FOO_H_ - -... all header contents ... - -#endif - //_FOO_H_ -- -In this way, the header will only be included once for the compilation -of any .cpp (of course, it still will be included many times for the -compilation of the whole project, so it has nothing to do with precompiled -headers). wxWindows is no exception and also uses include guards which should use -the above form, except for top-level headers which include files with identical -names, in which case you should use _FOO_H_BASE_. - -
-The precompiled headers greatly (we're speaking about orders of hundreds of
-percent here) reduce the compilation time. wxWindows uses them if the target
-compiler supports them (it knows about MS Visual C++, Borland C++ and g++).
-You should include all the headers included from
- -The start of a cpp implementation file after the heading might look like this:
- -
-#ifdef __GNUG__ -#pragma implementation "bitmap.h" -#endif - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#include <stdio.h> -#include "wx/setup.h" -#include "wx/list.h" -#include "wx/utils.h" -#include "wx/app.h" -#include "wx/palette.h" -#include "wx/bitmap.h" -#include "wx/icon.h" -#endif - -#include "wx/msw/private.h" -#include "assert.h" -- - -
Any header file should containg the following lines: -
-#ifdef __GNUG__ - #pragma interface "foo.h" -#endif --and the corresponding .cpp file: -
-#ifdef __GNUG__ - #pragma implementation "foo.h" -#endif -for g++ compilation. -
-
-
-
-
- -
-bool WXDLLEXPORT wxYield(void); -class WXDLLEXPORT MyClass; // (for forward declarations and real declarations) -WXDLLEXPORT_DATA(extern wxApp*) wxTheApp; -- -The reason for the strange syntax for data is that some compilers use different -keyword ordering for exporting data. - -
-There is a convention in wxWindows to prefix the accessors (i.e. any simple, in -general, inline function which does nothing else except changing or returning -the value of a member variable) with either Set or Get. - -
-The constants in wxWindows code should be defined using enum C++ -keyword (and not with #define or static const int). They -should be declared in the global scope (and not inside class declaration) and -their names should start with a wx prefix. Finally, the constants -should be in all capital letters (except the first 2) to make it easier to -distinguish them from the variables with underscores separating the words. - -
For example, file-related constants should be declared like this: -
-enum -{ - wxFILEOPEN_READ, - wxFILEOPEN_WRITE, - wxFILEOPEN_READWRITE -}; -- -
-
-It's really a trivial piece of advice, but remember that using forward declarations -instead of including the header of corresponding class is better because not -only does it minimize the compile time, it also simplifies the dependencies -between different source files. -
On a related subject, in general, you should try not to include other -headers from a header file. - -
-wxWindows provides the debugging macros wxASSERT, wxFAIL and
-wxCHECK_RET in
Also, please use wxFAIL_MSG("not implemented") instead of writing -stubs for not (yet) implemented functions which silently return incorrect -values - otherwise, a person using a not implemented function has no idea that -it is, in fact, not implemented. -
As all debugging macros only do something useful if the symbol -__WXDEBUG__ is defined, you should compile your programs in debug mode to profit -from them. -
- -