tags:

views:

356

answers:

6

What is best practice for C++ Public API?

I am working on a C++ project that has multiple namespaces, each with multiple objects. Some objects have the same names, but are in different namespaces. Currently, each object has its own .cpp file and .h file. I am not sure how to word this... Would it be appropriate to create a second .h file to expose only the public API? Should their be a .h file per namespace or per object or some other scope? What might be a best practice for creating Public APIs for C++ libraries?

Thanks For Any Help, Chenz

+1  A: 

I'd say it's best decided by you, and the type of 'library' this is.

Is your API provides one "Action"? or handles only one abstract "Data type"? examples for this would be zlib and libpng. Both have only one header that gives everything that is needed to perform what the libraries are for.

If your library is a collection of unrelated (or even related) classes that do, or not, the same goal, then provide each subset with it's own header. Major example for this will be boost.

LiraNuna
+2  A: 

It is sometimes convenient to have a single class in every .cpp and .h pair of files and to have the namespace hierarchy as the directory hierarchy.
For instance if you have this class:

namespace stuff {
  namespace important {
    class SecretPassword 
    {
       ...
    };
  }
}

then it will be in two files:

/stuff/important/SecretPassword.cpp
/stuff/important/SecretPassword.h

another possible layout might be:

/src/stuff/important/SecretPassword.cpp
/include/stuff/important/SecretPassword.h
shoosh
But when putting everything together in a single .so library, do I distribute a deep include directory structure?Chenz
Crazy Chenz
I mean .so or .dll
Crazy Chenz
@Crazy Chenz, yes, this is a possibility. This is how it is done in the Linux kernel for instance and also in boost to some degree.
shoosh
A: 

Great response LiraNuna.

Are you providing an API to an application or a library?

An application API will generally only provide methods that either query the state of an application or attempt to alter that state. In this case you'd generally have separate interface declarations in a separate header file. Your objects would then implement this interface to handle API requests.

A library will generally expose objects that can be re-used. In this case, generally speaking, your API is simply the public methods in the header file.

Josh
"Great response LiraNuna." So vote it up? :(
LiraNuna
Haha I generally respond then vote ;)
Josh
I have a core library that should be re-usable, and then a few namespaces that contain all the objects and helpers for applications that use the core. The core is what I want to "expose" a public API for.
Crazy Chenz
Just seems strange to have .h files that show the definitions of the private methods/vars in my distribution.
Crazy Chenz
Okay so my guideline there would be - reduce scope as much as possible.If I include 'foo.h', don't make me inherit a bunch of functions and objects that I don't care about. Consider STL - I #include <map> not <collections>.As long as your interface is complete and well-defined, having many includes in client code is preferable to bloat (imho).
Josh
Does the compiler not eliminate the bloat? In libraries like gtk and Xlib, you include gtk/gtk.h or X11/Xlib.h and thats it. Are they sacrificing conservation for cleaner code?
Crazy Chenz
I guess in those cases, I could be more specific, but they've added a convienence header file that includes bloat but allows me to not have to know everything else.
Crazy Chenz
heh... a #include <stl> might be nice to have (especially if the compiler gets rid of the "bloat")
Crazy Chenz
Sure, as I said - that is what I'd prefer. It sounds to me as though you're quite capable of making the right decision for your project. My last piece of advice - ask the clients (developers) what they'd prefer. Prepare yourself to hear **both**! :D
Josh
+1  A: 

G'day,

One suggestion is to take a look at the C++ idiom of Handle-Body, sometimes known as Cheshire Cat. Here's James Coplien's original paper containing the idiom.

This is a well known method for decoupling public API's from implementations.

HTH

Rob Wells
Another name for this idiom ( that I think has become more popular, but I might be wrong) is the "pimpl idiom" - pointer to implementation.
Michael Burr
@michael, you're right. that name has also been added but fairly recently iirc. handle/body was the original name Cope gave it in his 1991 book "Advanced C++ Programming Styles and Idioms" <http://www.amazon.com/dp/0201548550/>
Rob Wells
A: 

Here is what I'm used to do:

"Some objects have the same names, but are in different namespaces"

That's why namespaces exist.

"Would it be appropriate to create a second .h file to expose only the public API? "

You always should expose only the public API. But what means to expose public API? If it would be only to headers then, since public API relies on private API, the private API would be included by public API anyway. To expose a public API mark public functions/classes with a macro (which in case of Windows exports public functions to the symbol table; and probably it will be soon adopted by Unix systems). So you should define a macro like MYLIB_API or MYLIB_DECLSPEC, just check some existing libraries and MS declspec documentation. It is sufficient, usually non-public API will be kept in subdirectories so it doesn't attend library's user.

"Should their be a .h file per namespace or per object or some other scope?"

I prefer Java-style, one public class per header. I found that libs written in this way are far more clean and readable than those which are mixing file and structure names. But there are cases when I brake this rule, especially when it comes to templates. In such cases I give #warning message to not include header directly and carefully explain in comments what is going on.

doc
"But what means to expose public API?" I was thinking along the lines of reproducing all the headers for distribution without their private methods and vars.
Crazy Chenz
I mean.... without their private method prototypes and private variable declarations.
Crazy Chenz
That doesn't make sense IMO. In fact this would make your library only harder to understand and maintain. If someone has to extend your class, then he would probably like to see whole class structure and not only public and protected members. Class definition should be definitely kept in one header.
doc
A: 

I agree with what doc said - one class per file. 99.9% of the time!

Also, consider what filenames to use. It's generally a bad idea to have multiple headers of the same name in different directories, even though the classes they contain may well be in different namespaces.

Especially if this is a public API, you probably cannot control what include paths are defined by the user of your library, so a build may find the wrong one. Tweaking the order of include paths would definitely not be a solution I'd recommend!

We use a naming convention of Namespace-Class.h to explicitly identify classes in files.

Steve Folly
May I ask what you do with long namespaces? Let's say you have a class mylib::graphics::formats::JpegLoader. Name header Mylib_Graphics_Formats-JpegLoader.h? It is somewhat frustrating to use such headers. IMO the best way to avoid accidental inclusions is to force your library name be part of inclusion path, in our example inclusion would look like #include <mylib/graphics/formats/JpegLoader.h>. Until you have "mylib" in <> everything will be fine.
doc
Fortunately our namespaces aren't nested that deep; only one namespace, rarely 2, so it's not too bad. In what way is it frustrating - and what's the difference between `#include "Mylib-Graphics-Formats-JpegLoader.h"` or `#include "mylib/graphics/formats/JpegLoader.h"`? You still have to type the complete 'path' somehow?
Steve Folly
You may have#include <mylib/graphics/formats/Mylib-Graphics-Formats-JpegLoader.h> if you keep directory structure in respect to namespaces, and on my side it would be <mylib/graphics/formats/JpegLoader.h>. If you keep everything in one directory, then OK.
doc
@doc: ooh, yuk! :-) we use a flat directory tree and put the 'structure' into the file names. This prevents ambiguity when you have (in your example) 2 JpegLoader.h files. I can see if you force the users of your API to set their include paths to point to where `mylib` is then you don't have ambiguity. But you can't always guarantee users will do The Right Thing (or you can guarantee they *will* do The Wrong Thing!).
Steve Folly