views:

151

answers:

6

Hi All,

I have a question that bothers me for a long time.

I have a mathematical library, implemented as DLL. The library implements many types of mathematical functions. The mathematical functions are implemented in different classes based on their functionality. For example, all functions that implements polynomial equations are under CPolynom, all functions that implements differential equations are under CDifferential.

The DLL has to expose an interface. Now my question:

Option 1

I can implement in one header file, one interface class which includes all the “sub” interface methods of all practical classes => On one hand, I expose to the outside world only one header file with one class, on the other hand this class might be huge, including interface methods which are not related (i.e. someone wants the CPolynom functionality, he/she will have to include huge header file and construct huge interface class)

Option 2

I can implement interface class for each class in different header file. => On one hand I split classes to different files based on functionality. If someone wants a specific functionality, he/she will have to include only the relevant file. On the other hand, I can end up with many header files introduced to the outside world.

Which approach counts as more professional, more correct in software design discipline?

Thank you, David

A: 

Well, you could always go for option 2 and create a header, that will include all other headers, so that way, if someone doesn't care, he will just include 1 big header, otherwise, he will be able to include only what he needs.

Personally, I don't see anything wrong with one big header, when I try to use small headers as an user, I always have problems like "I need only 1 function from header X, 2 from header Y, ...." and after all, I end up with 15 includes to one library in each *.cpp file, which is annoying (so I actually create one big header myself :) ).

Ravadre
A: 

I think that you should implement interface for each class and put them in one header file. No need to produce lot of library headers in the world of precompiled headers.

Kirill V. Lyadvinsky
A: 

One header (or few, if there is a lot of interfaces and you can group them logically), but separate classes is an option too. Don't make one huge class with bunch of methods like you were going to do in option 1.

Eugene
+1  A: 

I generally implement one header per class. If you find yourself always needing a shotgun blast of headers because you need "one from column A and two from column B", that generally implies some sort of design code smell. For instance, you have a single responsibility spread across several classes instead of concentrated in a single class.

legalize
A: 

The size of the header file is relevant only in terms of how long it takes to compile. Unused declarations will not impact performance, and your code size is already impacted by shipping all the functions in a DLL instead of statically linking only the needed functions.

Have you considered putting a COM interface on the library? Instead of shipping a separate .h file your users can simply:

#import "mathFunctions.dll" named_guids

Automatically declared smart pointers then make the functions usable with no further manual declarations or even cleanup. You can define your documentation in the IDL, which will then appear in tooltips in the IDE when your clients go to use your code. Your code is also reusable in all Microsoft languages from VB3-6 and wscript and .Net.

double myFunc(double x)
{
  double a=1, b=2, c=3, y=0;
    MathLib::PolynomPtr polynom(CLSID_CPolynom, 0, CLSCTX_INPROC_SERVER);
    y = polynom->someFunction(a, b, c, x); // use it somehow
    return y;
}

Used in-proc, COM adds only about 16 cycles of overhead to the execution of each function. Because it's a smart pointer, you do not have to clean it up. And I didn't include it above, but as with anything external you should add basic try/catch functionality wrappers:

catch (_com_error &e) { printf("COM error: %08x %s\n", e.Error(), e.Description()) };
John Deters
A: 

Option 2 would look natural and professional to everybody.

This is the way the large majority of libraries are done.

However, grouping small related classes in the same header (but still having several headers for the whole API) sounds very reasonable.

The biggest disadvantages I see of option 1 are: - Everything in a big class might be difficult to handle: when a developer is busy on using CPolynom, having its declaration lost between CDifferential and other class would be painful. - Using a namespace is more appropriate to aggregate classes, than a bigger, "mother" class.

In short, I would choose option 2, with all classes under the library namespace.

Jem