Professional C__ - Marc Gregoire [434]
// WebHost.h
#include "netwrklib.h"
class WebHost
{
// Omitted for brevity
protected:
Connection* mConnection;
};
The corresponding source file puts a new face on the functionality contained in the netwrklib library. First, the constructor builds a HostRecord for the specified host. Because the WebHost class deals with C++ strings instead of C-style strings, it uses the c_str() method on inHost to obtain a const char*, then performs a const cast to make up for netwrklib’s const-incorrectness. The resulting HostRecord is used to create a Connection, which is stored in the mConnection data member for later use:
WebHost::WebHost(const string& inHost)
{
const char* host = inHost.c_str();
HostRecord* theHost = lookupHostByName(const_cast mConnection = connectToHost(theHost); } Subsequent calls to getPage() pass the stored connection to the netwrklib’s retrieveWebPage() function and return the value as a C++ string: string getPage(const string& inPage) { const char* page = inPage.c_str(); string result = retrieveWebPage(mConnection, const_cast return result; } Networking-savvy readers may note that keeping a connection open to a host indefinitely is considered bad practice and doesn’t adhere to the HTTP specification. We’ve chosen elegance over etiquette in this example. As you can see, the WebHost class provides an object-oriented wrapper around the C library. By providing an abstraction, you can change the underlying implementation without affecting client code, and you can provide additional features. These features can include connection reference counting, parsing of pages, or automatically closing connections after a specific time to adhere to the HTTP specification and automatically reopening the connection on the next getPage() call. Linking with C Code In the previous example, we assumed that you had the raw C code to work with. The example took advantage of the fact that most C code will successfully compile with a C++ compiler. If you have only compiled C code, perhaps in the form of a library, you can still use it in your C++ program, but you need to take a few extra steps. In order to implement function overloading, the complex C++ namespace is “flattened.” For example, if you have a C++ program, it is legitimate to write: void MyFunc(double); void MyFunc(int); void MyFunc(int, int); However, this would mean that the linker would see several different names, all called MyFunc, and would not know which one you want to call. Therefore, all C++ compilers perform an operation which is referred to as name mangling and is the logical equivalent of generating names as follows: MyFunc_double MyFunc_int MyFunc_int_int To avoid conflicts with other names you might have defined, the generated names usually have some characters which are legal to the linker but not legal in C++ source code. For example, Microsoft VC++ generates names as follows: ?MyFunc@@YAXN@Z ?MyFunc@@YAXH@Z ?MyFunc@@YAXHH@Z This encoding is complex and often vendor-specific. The C++ standard does not specify how function overloading should be implemented on a given platform, so there is no standard for name mangling algorithms. In C, function overloading is not supported (the compiler will complain about duplicate definitions). So, names generated by the C compiler are quite simple; for example _MyFunc. Now, if you compile a simple program with the C++ compiler, even if it has only one instance of the MyFunc name, it will still generate a request to link to a mangled name. But, when you link with the C library, it cannot find the desired mangled name, and the linker will complain. Therefore, it is necessary to tell the C++ compiler to not mangle that name. This is done by using the extern "language" qualification in both the header file (to instruct the client code to create a name compatible with the specified language) and,