DiscussionThe more widely distributed your library, and the less control you have over the build environment of all of its clients, the fewer the types that the library can reliably use in its external interface. Interfacing across modules involves binary data exchange. Alas, C++ doesn't specify standard binary interfaces; widely distributed libraries in particular might need to rely on built-in types like int and char to interface with the outer world. Even compiling the same type using different build options on the same compiler can cause binary-incompatible versions of the type. Typically, either you control the compiler and options used to build the module and all its clients, and you can use any typeor you don't, and you can use only platform-provided types and C++ built-in types (even then, document the size and representation you expect for the latter). In particular, never mention standard library types in the interface of a module unless all other modules that use it will be compiled at the same time and with the same standard library source image. There is a tradeoff between the problems of using types that can't be correctly understood by all clients, and the problems of using a low level of abstraction. Abstraction is important; if some clients understand only low-level types, and you must therefore use those, consider also supplying alternate operations that use higher-level types. Consider a SummarizeFile function that takes the file to be processed as a parameter. There are three common options for the parameter: It can be a char* that points to a C-style string containing the file's name; a string that containers the file's name; or an istream or a custom File object. Each of these choices is a tradeoff:
Even when you choose to use a lower-level abstraction in a module's external interface, always use the highest level of abstraction internally and translate to the lower-level abstraction at the module's boundary. For example, if you will have non-C++ clients, you might use opaque void* or int handles to client code, but still use objects internally, and cast only at the module's interface to translate between the two. |