Redirection Through C++ Function Pointers
by Bill Trudell

Example 1: 

typedef int (*PFI)(int arg);             // C or C++
typedef int (Classname::*PFI)(int arg);  // C++ only

Listing One
// Declaration for the Logger Class
#if !defined(LOGGER_H_INCLUDED)
#define LOGGER_H_INCLUDED
using namespace std;    // for cout
class Logger
{
    public:
        // Singleton Pattern Instance Accessor Function
        static Logger* Instance();
        // Declare Type Definitions for the static and non-static
        // forms for a Pointer to a Function that accepts several
        // fixed arguments followed by a variable argument list
        // (common in a function that has a format statement)
        typedef bool (*PFLogMsgS)(bool bNoOutput, const char* szFormat,...);
        typedef bool (Logger::*PFLogMsgNS)(bool bNoOutput,
                                           const char* szFormat,...);
        // Handy macros to make calling the logging function easier.
        // The syntax in the non-static case is tedious.
        #define LOG_MSG_S (Logger::getLogMsgS())
        #define LOG_MSG_NS(pObject) ((pObject)->*(pObject->getLogMsgNS()))

        // Macro if using an instance
        #define LOG_MSG_NSi(object) ((object).*(object.getLogMsgNS()))
        ~Logger(void){ delete _instance; _instance = NULL; }

        // Declare accessors for the function pointers
        static PFLogMsgS  getLogMsgS(void)        { return m_pLogMsgS;  }
               PFLogMsgNS getLogMsgNS(void) const { return m_pLogMsgNS; }
        typedef enum
        {
            MINIMAL,
            VERBOSE
        } LOG_QUALITY;
        LOG_QUALITY GetQuality(void) const { return m_eLogQuality; }
        void SetQuality(LOG_QUALITY quality = MINIMAL);
    protected:
        // Singleton Pattern uses a protected Ctor
        Logger(LOG_QUALITY quality = MINIMAL);
    private:
        // Declare storage for a pointer to the instance
        static Logger* _instance;
        // Declare storage for pointers to the logging function
        static PFLogMsgS  m_pLogMsgS;
               PFLogMsgNS m_pLogMsgNS;
        void SwitchLoggingFunctions(LOG_QUALITY quality);
        // Logging Functions, Static (S) and Non-Static (NS) Forms
        static bool Verbose_S(bool bNoOutput, const char* szFormat,...);
        static bool Minimal_S(bool bNoOutput, const char* szFormat,...);
        bool Verbose_NS(bool bNoOutput, const char* szFormat,...);
        bool Minimal_NS(bool bNoOutput, const char* szFormat,...);
    private:
        LOG_QUALITY m_eLogQuality;  // MINIMAL or VERBOSE
};
#endif  // !defined(LOGGER_H_INCLUDED)


Listing Two
// Definition for Logger Class Functions
#include "stdafx.h"
#include <iostream>
#include <stdarg.h>
#include "Logger.h"

// Initialize static class data (once before program runs)
Logger* Logger::_instance = 0;
Logger::PFLogMsgS Logger::m_pLogMsgS = Logger::Verbose_S;

// Implement the Instance method
Logger* Logger::Instance()
{
    // If first time called, make a new one.
    // (For all time, there will be only one unique instance.)
    if (_instance == 0)
    {
        _instance = new Logger;
    }
    return _instance;
}
Logger::Logger(LOG_QUALITY quality /* = MINIMAL */ )
{
    SwitchLoggingFunctions(quality);
}
void Logger::SetQuality(LOG_QUALITY quality /* = MINIMAL */ )
{
    SwitchLoggingFunctions(quality);
}
void Logger::SwitchLoggingFunctions(LOG_QUALITY quality)
{
    switch ( quality )
    {
        case MINIMAL:
            m_eLogQuality = quality;
            m_pLogMsgS  = Logger::Minimal_S;
            m_pLogMsgNS = Logger::Minimal_NS;
            break;
        case VERBOSE:
            m_eLogQuality = quality;
            m_pLogMsgS  = Logger::Verbose_S;
            m_pLogMsgNS = Logger::Verbose_NS;
            break;

        default:
            m_eLogQuality = MINIMAL;
            m_pLogMsgS  = Logger::Minimal_S;
            m_pLogMsgNS = Logger::Minimal_NS;
            break;
    }
}
// This function looks exactly the same as Verbose_NS,
// except it's static and doesn't get a this pointer.
bool Logger::Verbose_S(bool bNoOutput, const char* szFormat,...)

{
    // Setup for varg processing
    va_list vl;
    va_start( vl, szFormat);

    // Assume 1st 2 vargs are the filename and line number,
    // and ignore other arguments for this demonstration
    char* pFileName   = va_arg( vl, char* );
    int   nLineNumber = va_arg( vl, int );

    // Format the simple message
    char buffer[256];
    sprintf(buffer, szFormat, pFileName, nLineNumber );

    // Allow for output suppression on the fly, especially when doing millions
    // of iterations for timing tests. If caller wants output, use stdout 
    // device for this demonstration knowing there are many other devices
    // that could be used.
    if ( !bNoOutput)
    {
        printf(buffer);
    }
    // Finish the varg processing
    va_end( vl );
    return true;
}
bool Logger::Verbose_NS(bool bNoOutput, const char* szFormat,...)
{
    // Setup for varg processing
    va_list vl;
    va_start( vl, szFormat);
    // Assume 1st 2 vargs are the filename and line number,
    // and ignore other arguments for this demonstration
    char* pFileName   = va_arg( vl, char* );
    int   nLineNumber = va_arg( vl, int );

    // Format the simple message
    char buffer[256];
    sprintf(buffer, szFormat, pFileName, nLineNumber );

    // Allow for output suppression on the fly, especially when doing millions
    // of iterations for timing tests. If caller wants output, use stdout 
    // device for this demonstration knowing there are many other devices
    // that could be used.
    if ( !bNoOutput)
    {
        printf(buffer);
    }
    // Finish the varg processing
    va_end( vl );

    return true;
}
bool Logger::Minimal_S(bool bNoOutput, const char* szFormat,...)
{   return true;    }
bool Logger::Minimal_NS(bool bNoOutput, const char* szFormat,...)
{   return true;    }

// End of Logger.cpp


Listing Three
// Sample Code. Instantiate the Logger by calling the Instance Method
// Set the Quality Level, then Use the Log Macros

Logger* pLogger = Logger::Instance();
pLogger->SetQuality(Logger::VERBOSE);
bool bResult;
bResult = LOG_MSG_S(false, "File: %s Line: %d Msg: Hello\n", __FILE__, __LINE__ );
bResult = LOG_MSG_NS(pLogger)(false, "File: %s Line: %d Msg: World\n", __FILE__, __LINE__ );





1

