Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to order functions in C++?

Tags:

c++

function

I'm not sure how to order my functions in C++. In C, I simply placed a function that uses another function below that function, as closely as possible - that's pretty common. Like this:

void bar()
{
}

void foo()
{
    bar();
}

However, in C++, there are several types of functions:

  • Free functions
  • Private member functions
  • Public member functions
  • Static member functions

I'm currently making my function order dependent on how they are ordered in the .hpp file, e.g.:

class Foo_bar {
public:
    Foo_bar();
    void foo();
private:
    int some_member;
    void bar();

But now, if the constructor uses foo() or bar(), these will be below the constructor in the source file, inconsistent with my usual ordering. I could of course reorder my header to take account of that:

class Foo_bar {
private:
    int some_member;
    void bar();

public:
    void foo();
    Foo_bar();

But I think that's a mess.

Furthermore, in Java, the opposite to my first example seems to be common:

void foo()
{
    bar();
}

void bar()
{
}

That's probably due to the top-down thinking common in OOP, in contrast to the bottom-up thinking common in procedural/functional programming. However, with free functions that don't have prototypes, this top-down style is not possible.

Is it even possible to order functions in C++ in a consistent way?

like image 902
forneo Avatar asked Nov 28 '10 13:11

forneo


4 Answers

It's possible. You have to use forward declaration.

Declare a function before defining it, and other functions will see it without problem even if they are defined before.

So, you should be able to do this in C++:

void bar();  // forward declaration; note that function bar isn't defined yet

void foo()
{
    bar();   // foo knows that bar is declared, so it will search for bar's definition
}

void bar()   // here bar is defined, so foo will use this when needed
{
}
like image 185
darioo Avatar answered Sep 20 '22 22:09

darioo


It's a pretty good question actually, because readability has a major impact on whoever will read the code after you.

There are 3 kinds of people who will read the code of a class:

  • those who wish to uses it (and don't care much about its internals)
  • those who wish to inherit from your class (and don't care much about its internals)
  • those who wish to hack on your class, and thus really care of its internals

For this reason, I try to order the headers so that any user may stop once he got what he was looking for, which means:

class Foo
{
public:
  // types
  // static methods
  // methods (usually constructors,
  //          then simple accessors,
  //          then more complicated stuff)

protected:
  // same pattern

private:
  // same pattern
  // attributes
};

// Free functions about this class

// Implementation of inline / template methods

Sometimes I need to declare some types beforehand even though they are private, but this is rare. The goal of this ordering is to absolutely minimize the amount of stuff a reader has to read before he gets what he wants (and stops reading and goes back to what he was doing before having to interrupt himself to look at your code).

Then, regarding "helper" methods, it depends on the type of code:

  • for template code, I use a "details" namespace, it's both clear to the reader that he should not be worried about it and it isolate the names in their own namespace so that they do not pop up in code completion tools
  • for regular code, I use an anonymous namespace within the source file, which is even better since then it actually generates invisible symbols and I don't run the risk of violating ODR.

If some code may require a lot of helpers, I tend to create a dedicated header file in the source directory, giving the following structure:

include/
  foo.hpp

src/
  fooImpl.hpp --> #include "foo.hpp"
  foo.cpp     --> #include "fooImpl.hpp"

in order to provide a list of declarations to the reader, because it's easier to browse a list of declarations than to extract the declarations from a list of definitions, whatever the indentation and style.

And of course, always to make it easier, I always order the list of declarations and the list of definitions equally...

like image 23
Matthieu M. Avatar answered Sep 17 '22 22:09

Matthieu M.


You declare the class in a header file, right? And implement most of it in a separate file? If you simply implement the constructor in the implementation file and not in the header, I don't think you'll experience the problem you mentioned (because the entire header will be seen before the constructor is seen to call foo() or bar().

like image 32
John Zwinck Avatar answered Sep 21 '22 22:09

John Zwinck


Ordering free functions in C++ obeys the same rules as you mentioned, but like darioo said, you can forward declare them and order the function definitions any way you want. That is also the preferred way: declare everything in header, and put ALL definitions in the source file. This is not possible for templates though, without some non-trivial and non-general anti-template workarounds.

In a class, things are usually different, because there is almost no cases where you fully implement your class in a header, thus the declarations are always read when you're defining the functions in the source file.

I usually order functions in "function", and group eg. getters and setters, constructor/destructor (if possible).

like image 35
rubenvb Avatar answered Sep 19 '22 22:09

rubenvb