7

Recently I've been browsing source code of large applications written in C++ to learn a bit but I couldn't help but notice that most if not all use a lot of IFDEFs and class-less functions (where they could have been class members/methods).

An example is Qt Creator IDE source code:

http://qt.gitorious.org/qt-creator/qt-creator/blobs/master/src/app/main.cpp

If you notice, it has a bunch of functions around the main() function; one of them, for example, is:

static inline void toHtml(QString &t)

the above method is defined outside while I think it could have been part of some utility class maybe.

Also, I think IFDEFs make the programs messy (again my opinion).

My question is: is it just an accepted practice in C++ world to mix procedural and OO code like that?

3
  • 1
    This is a super subjective question - C++ affords you the ability to mix paradigms. You don't necessarily need to build utility classes (unlike, say, in Java, where everything has to be in a class), and conditional compilation is necessary because of disparate platforms. If you look at boost source code (arguably some of the best C++ code, though also some of the most advanced and opaque), there is a lot of conditional compilation involved. Other reasons could just be that Qt/Nokia/whoever defined a specific coding style, or the code itself was written and never changed.
    – wkl
    Commented May 13, 2013 at 16:24
  • @birryree: Could you post that as an answer? Commented May 13, 2013 at 16:35
  • 1
    For another example you can take a look at LibreOffice's source code; it's quite old/mayure, but also overengineerd and might be able to provide you with a "how things have been done" view: cgit.freedesktop.org/libreoffice/core/tree
    – phw
    Commented May 13, 2013 at 21:51

5 Answers 5

15

It is a rather subjective question - there are many schools of practice for writing C++ code.

C++ affords you the ability to pick and choose what paradigms you want to use for writing your code. The language allows you to use procedural, object-oriented, generic, and functional constructs (especially with C++11 features).

You don't necessarily need to build utility classes (unlike, say, in Java, where everything has to be in a class), as static functions in a class may not be required and can just be standalone free functions.

Conditional compilation is a necessity because of disparate platforms. I worked in defense, and have written code using Qt, boost, libraries for video games, and have worked on a variety of platforms including Linux, HP-UX, AIX, Windows, IRIX, and Mac OSX - platforms are different enough that code written for one does not necessarily work on a different platform. Some easy examples are:

  • Endianess - Some architectures (like x86) are little endian, but many other architectures (like SPARC) are big endian. Networking is also reliant on big endian addressing. When you write code across different architectures, sometimes you need to conditionally compile in code that supports such endian differences.

  • Different library calls - Windows uses winsock as its networking API, and it's similar to BSD Sockets used by Unix and Unix-derivatives. However, it is different enough that the function calls aren't similar. Additionally, there are library calls that exist in some flavors of Unix that don't exist in other flavors, or derivatives, so conditional compilation is needed for that too.

  • Compiler differences or versioning differences - Different versions of compilers, or different compilers altogether, may support functionality/libraries that aren't supported by other compilers.

Even if you use a library like Qt, which aims to be cross-platform, there is still conditional compilation happening, as you found out. These cross-platform libraries are there to reduce your own needs to do conditional compilation.


Additionally, coding styles and standards may be influencing how code is written.

Just more anecdotes from my past - C++ can be written in many ways as influenced by internal standards. For example, some organizations restrict the use of the C++ Standard Library, especially in regards to using the standard containers (like std::vector and std::list) - this may be due to the environment involved (like embedded systems).


Ultimately, it does come down to this: there are many ways to write C++, and it is acceptable to mix and match different paradigms in a single C++ program and code base, because there may be better/simpler ways to express something in one paradigm than to be locked into using a single pattern for an entire code base.

If you want to look at large C++ code bases that have high code quality, I will say that Boost and Qt are among the better examples.

Generally and widely accepted conventions and idioms for C++ programming are provided in books like Effective C++ and More Effective C++

4
  • 1
    Great answer... additional point: age of the project. A vast majority of large C++ code bases have been around 10, 15 or even 20 years (QT began development in 1991). They date back to when C++ was not much more than "C with Classes" - and OO was a new paradigm. Much has changed, but that code remains....
    – mattnz
    Commented May 13, 2013 at 22:17
  • 2
    There is a fourth reason for conditional compilation: Feature switches (code that should only be compiled in if certain features are needed/available. Commented May 14, 2013 at 10:29
  • You could also mention wxWidgets coding standards that almost banned C++ from C++ code at a time :)
    – Morwenn
    Commented Jun 7, 2013 at 9:06
  • 1
    "because there may be better/simpler ways to express something in one paradigm than to be locked into using a single pattern for an entire code base": In case of a code base that is maintained by several programmers over many years, having different paradigms in the code base might add overhead if some programmers are not familiar with all the paradigms.
    – Giorgio
    Commented Jun 7, 2013 at 10:05
3

Sometimes the "class" part of a utility class does nothing more than act as a pseudo-namespace. There is no instance state needed, just parameters passed into a function. For example the Math class in C#. In that case you may as well just have free functions in a namespace.

Sometimes behavior should be a property of the "environment" not the object. For example a save() function may be layer/environment specific and should be a free function in that layer. The object may visit many layers (physical or logical) where saving may not be relevant.

2

While I agree with others that the question is subjective, the two examples you give are viewed very differently by the C++ community:

  • #ifdef sparkled around C++ code is a bad practice. System-dependent code is best kept isolated in separate files and handled by the build system. Otherwise you get the mess that you saw in the cpp file you sent a link to.
  • Free functions in C++ are a good thing. Instead of giving lengthy explanation here, I suggest reading Scott Meyer's classic text on the topic: How Non-Member Functions Improve Encapsulation
4
  • Thanks so much @Nemanja :) But, would it not make the code easier to navigate, understand if the toHtml() function was part of some HTMLUtil class or HTMLUtil namespace? This way the code reader can know that this method belongs to the family of HTML related functions which are encapsulated in a static class or namespace rather than a free floater with no connection to any family? Commented Jun 7, 2013 at 13:07
  • @birryree would be also cool to have your perspective on this. thanks. Commented Jun 7, 2013 at 13:11
  • toHtml() is just a helper function (poorly named, IMHO), that is used just to add some HTML tags to the help text. It does not need to be visible outside the module where it is declared, as it can't be used from there anyway. Ideally, it would be even more hidden, as it is called from exactly one place - for instance a nested function in languages that support them. Commented Jun 7, 2013 at 13:32
  • More general functions that are meant to be used from different places are, as you say, best grouped together via namespaces. For instance, take a look at Boost libraries. Commented Jun 7, 2013 at 13:34
0

It is generally accepted in many worlds. In fxCop for C# for example, it will flag you for not making methods static when they use no member variables. The idea is that a class should only define enough of a public interface to protect its invariants; the rest is the responsibility of the consumer, who knows best how the class will be consumed.

I'm not sure I would go so far as to consider it universally accepted, but it is a common practice.

0

Like what birryree said, this is indeed a subjective question. There are many ways to program in a large scale application. The type of application can also play a big part on the way you want to program your application.

It is good to look into Component-based programming if the project is really big scaled. This however should also be considered in a case-by-case basis to see if your project really needs it.

Google Component based programming for more info.

Here is the wiki page for it: http://en.wikipedia.org/wiki/Component-based_software_engineering

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.