3

I am a total noob when it comes to any language in the C family of programming languages.(C, C++, C#, etc).

I am trying to understand the basics about how a physics engine works, and I found Randy Gaul's tutorial on how to make a 2d physics engine from scratch. I downloaded the source code from this repo and I tried to understand what was going on. I am a decent (not the best) Java programmer, so I know whats going on, until I hit this section.

There is an enum in a structure/class called shape:

struct Shape
{
  enum Type
  {
    eCircle,
    ePoly,
    eCount
  };
...
}

And then later in Collision.h:

typedef void (*CollisionCallback)( Manifold *m, Body *a, Body *b );
extern CollisionCallback Dispatch[Shape::eCount][Shape::eCount];

in Collision.cpp:

CollisionCallback Dispatch[Shape::eCount][Shape::eCount] =
{
  {
    CircletoCircle, CircletoPolygon
  },
  {
    PolygontoCircle, PolygontoPolygon
  },
};

CircletoCircle, CircletoPolygon, PolyontoCircle, PolygontoPolygon are all functions that are in the form functionName( Manifold *m, Body *a, Body *b )

From my poor understandings, I believe that this guy declared a type that returns void called CollisionCallBack with all the paremeters, to save up some pain from typing up void Name(Manifold *m, Body *a, Body *b) all the time. The line with the extern is just to tell the compiler to hush up.

What I don't get is that chunk of code in Collision.cpp. So here is a list of things about this that I don't understand.

  • Firstly, what is with those square brackets? It definitely isn't an array, because he used it like this Dispatch[A->shape->GetType( )][B->shape->GetType( )]( this, A, B ); getType() gives you the type of the enum the shape in object A is.

  • Secondly, they typedef makes this look like a method, yet you can assign a value to the method, or is this something else that you can do with C++? How does this work?

  • Thirdly, I ran the application and it worked, so how does this actually call the methods without even giving parameters to the methods?
  • Fourthly, and finally, why did he put Shape::eCount inside that block?

Thanks for your attention so far, I know this is very long, because I am terrible at explaining. I would prefer if someone could provide me with a java equivilent (if it exists) for this or at least answer the four questions I asked above.

Thanks in advance.

Fish
  • 1,689
  • 1
  • 18
  • 28
  • Java equivalent would use array Java 8's Function class OR array of interface/classes that conform to some interface. – Brandon Apr 13 '16 at 03:14

3 Answers3

3

Firstly, what is with those square brackets? It definitely isn't an array, because he used it like this Dispatch[A->shape->GetType( )][B->shape->GetType( )]( this, A, B );

Yes, it IS an array. It's a 2-dimensional array of function pointers.

Secondly, they typedef makes this look like a method, yet you can assign a value to the method.

As previously mentioned, it's an array. The assignment initialises the array with the relevant function pointers.

Thirdly, I ran the application and it worked, so how does this actually call the methods without even giving parameters to the methods?

It did give parameters to the methods. That's what the (this, A, B) part of your invocation example is.

Fourthly, and finally, why did he put Shape::eCount inside that block?

That's an enumeration trick commonly used to easily get the number of enumerations defined. You use it when you have automatic enumeration values (which begin at 0). So eCircle is 0, ePoly is 1, and eCount is 2 which is the total number of enumerations (not including eCount which is a special value not intended to be used as an actual shape).

paddy
  • 60,864
  • 6
  • 61
  • 103
2

The typedef declares CollissionCallback to be a discrete type. The type is a pointer to a function that takes the listed three parameters, then returns a void.

Dispatch is a regular two-dimensional array declaration. It's abusing the fact that enum values are consecutively numbered starting at 0:

  enum Type
  {
    eCircle,
    ePoly,
    eCount
  };

After all is said and done, the enum Type's eCircle is equivalent to 0, ePoly to 1, and eCount to 2. The values in an enum, by default, are numbered starting at 0, so the array declaration is really equivalent to:

 CollisionCallback Dispatch[2][2] =

... and is initialized with pointers to functions. Remember that CollissionCallback is a type that's a pointer to a function.

This is a somewhat hacky way to initialize a 2x2 array of function pointers, that's all.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
1

Ok... Lets solve this Top-Down... First,

struct Shape
{
  enum Type
  {
    eCircle,
    ePoly,
    eCount
  };
...
}

I will deal with the enum here: Except for 'enum class', enum's members are exported to their surrounding namespace. The name of a class is also a namespace. Hence you must address any of those enumerations as Shape::eCircle, etc... $A: their values are known at compile time


And then later in Collision.h:

typedef void (*CollisionCallback)( Manifold *m, Body *a, Body *b );
extern CollisionCallback Dispatch[Shape::eCount][Shape::eCount];

typedef void (*CollisionCallback)( Manifold *m, Body *a, Body *b ); defines a function pointer which is basically a type to store the address of a function You have it assigned to the address of any function of that signature. See this background on function pointers.

extern CollisionCallback Dispatch[Shape::eCount][Shape::eCount]; defines a two dimensional array of CollisionCallbacks. Remember, the value of Shape::eCount is known at compile time. From Shape::Type we see that the member eCount is at the 2nd index (2), remember arrays starts from 0. So,

extern CollisionCallback Dispatch[Shape::eCount][Shape::eCount];

in your specific case, effectively translates to

extern CollisionCallback Dispatch[2][2];

The extern tells the compiler to find its definition in another translation unit


CollisionCallback Dispatch[Shape::eCount][Shape::eCount] =
{
  {
    CircletoCircle, CircletoPolygon
  },
  {
    PolygontoCircle, PolygontoPolygon
  },
};

Its basically defining a variable named Dispatch which is a 2D array; and it's being initialized.


  • Firstly, what is with those square brackets? It definitely isn't an array, because he used it like this Dispatch[A->shape->GetType()][B->shape->GetType( )]( this, A, B ); getType() gives you the type of the enum the shape in object A is.

He is indexing the array and calling the function pointer in that index. The this is the first implicit parameter required by every member function. See an extensive write-up here.


  • Secondly, they typedef makes this look like a method, yet you can assign a value to the method, or is this something else that you can do with C++? How does this work?

See this


  • Thirdly, I ran the application and it worked, so how does this actually call the methods without even giving parameters to the methods?

The parameters were binded.


  • Fourthly, and finally, why did he put Shape::eCount inside that block?

Inside what block? If you meant the struct Shape, its to provide scoped enumeration. If you meant elsewhere, its to retrieve the integer value of Shape::eCount


I hope this helps. :-)

Community
  • 1
  • 1
WhiZTiM
  • 21,207
  • 4
  • 43
  • 68