UNISA Chatter – Design patterns in C++ Part 1: Visitor Pattern

Blue Doctor Man Sitting at a Computer and Viewing an Xray of a Head Clipart Illustration See UNISA – Summary of 2010 Posts for a list of related UNISA posts. This post is one of the summary posts I will be building up over the next couple of months, so if you are following this topic or completing the same course as I this year, you may want to bookmark this post and come back occasionally for a peek and to give “candid” feedback.

This course is based on QT4 (https://en.wikipedia.org/wiki/Qt_(toolkit)), which made me cringe as I am heavily into and in love with Visual Studio 2010. After spending several evenings unzipping tar’s, battling to find instructions on installation, setup and dependencies, followed by a dismal experience in the IDE we are forced to use for this course and having to build everything (libraries, utilities, …) myself, I yearn to get back into Visual Studio and the near seamless installation experience.

The funny part is that while I setup this special development environment, I must have installed and configured the Team Foundation Server and Visual Studio environment in excess of 25 times using our VM Rangers factory … few clicks and it works, compared to a few hours slog every evening … but nevertheless, something new every day keeps the boredom away I guess.

What is really fun, is the short return to C++, after years of C# distractions :)

QT and Environment Summary

Terminology Description Example
Makefile The makefile contains the instructions, such as rules for building files, target executables and dependencies. The utility make is used to manage the building of the project using the makefile as the treasure map or build recipe. See https://blogs.msdn.com/willy-peter_schaub/pages/unisa-makefile-example.aspx for an example.
Project File Project file describes the project by listing all files, options and other information needed to build the project. TEMPLATE = app | lib SOURCES += sample.cpp
QApplication Main application object needed by all Qt GUI applications. Typically created at the start of the main() function.  
QMake Qt tool that can be used to generate makefiles based on a project file.  
QString Dynamic Qt string implementation class with support for Unicode.  
TEMPLATE Defines which templated makefile to use, i.e. app for application, lib for library. TEMPLATE = app | lib SOURCES += sample.cpp

Design Pattern Summary

Terminology Description
Design Patterns

You best refer to the book “Gang of Four” for the complete story. In essence we have three main categories of patterns that define a name, a description, an abstract description of the design problem and discussion on pros and cons of patterns:

  • Creational Patterns – management of objects
  • Structural Patterns – connection of objects to form more complex objects
  • Behavioural Patterns – organization of code and object communication
Pattern: Visitor
  • Behavioural design pattern
  • Describes how to separate code for re-use, keeping a clear separation between an algorithm (logic) from an object structure that the algorithm operates on.
    • This approach allows us to extend the feature set of operations of an existing object ecosystem without changing the ecosystem (plumbing).
    • It is a way of separating operations to be performed on selected objects in some organised collection.

image

Example of the CodeVisitor class, which is an extension of the FileVisitor, as implemented in the Ezust Utilities. See Qt – Cross-platform application and UI framework for more information.

Header File

    1: #ifndef _CODE_VISITOR_H_
    2: #define _CODE_VISITOR_H_
    3:  
    4: #include <filevisitor.h>
    5: #include <QStringList>
    6:  
    7:  
    8: /**
    9:    This program will visit every selected file
   10:    in or below the specified directory and produce a list
   11:    of the names and optionally the file size.
   12: */
   13: //start
   14: class CodeVisitor : public FileVisitor {
   15:   public:
   16:     CodeVisitor(QString filter = "*", bool recursive = true, int displayType = 0, bool verbose = false):
   17:             FileVisitor(filter,recursive){}
   18:     CodeVisitor(QStringList filterList = "*", bool recursive = true, int displayType = 0, bool verbose = false);
   19:     void processFile(QString filename);
   20:     QString getResultString() const;
   21:     int getNumFiles() const;
   22:     QString getFileSizeInfo(QString filename) const;
   23:  private:
   24:     int m_NumFiles;
   25:     int m_DisplayType;
   26:     bool m_Verbose;
   27:     QStringList m_Result;
   28: };
   29: //end
   30: #endif

Source File

    1: #include "codevisitor.h"
    2: #include <QDebug>
    3: #include <QFile>
    4: #include <QTextStream>
    5:  
    6:  
    7: CodeVisitor::CodeVisitor(QStringList filterList, bool recursive, int sizing, bool verbose) :
    8:     FileVisitor(filterList, recursive)
    9: {
   10:     m_NumFiles = 0;
   11:     m_DisplayType = sizing;
   12:     m_Verbose = verbose;
   13: }
   14:  
   15: //start id="processfile"
   16: void CodeVisitor::processFile(QString filename) {
   17:     QString tempOutput = filename;
   18:  
   19:     // First check if we have a token and if yes, if file matches
   20:     if ( m_Verbose )
   21:     {
   22:         tempOutput.append(" \t");
   23:         tempOutput.append(getFileSizeInfo(filename));
   24:     }
   25:  
   26:     // Increment files processed
   27:     ++m_NumFiles;
   28:  
   29:     // Move stuff to output
   30:     m_Result << tempOutput;
   31: }
   32: //end
   33:  
   34: QString CodeVisitor::getResultString() const {
   35:     return m_Result.join("\n");
   36: }
   37:  
   38: QString CodeVisitor::getFileSizeInfo(QString fileName) const {
   39:     QFile file(fileName);
   40:     QFileInfo fileInfo(file);
   41:     QString fileSize;
   42:     double size = fileInfo.size();
   43:     if ( m_DisplayType == 2 )
   44:     {
   45:           size = size / 1000000;
   46:           fileSize = QString("size: %1 megabytes").arg(size);
   47:     }
   48:     else
   49:     if ( m_DisplayType == 1 )
   50:     {
   51:           size = size / 1000;
   52:           fileSize = QString("size: %1 kilobytes").arg(size) ;
   53:     }
   54:     else
   55:     {
   56:           fileSize = QString("size: %1 bytes").arg(size) ;
   57:     }
   58:     return fileSize;
   59: }
   60:  
   61: int CodeVisitor::getNumFiles() const {
   62:     return m_NumFiles;
   63: }

Sample Output

Test Arguments –> -d c:\temp\subdirectory -v -k

Files Processed: 12

C:/temp/subdirectory/AcGenral.dll size: 2175.49 kilobytes
C:/temp/subdirectory/AcLayers.dll size: 559.616 kilobytes
C:/temp/subdirectory/AcRes.dll size: 2.56 kilobytes
C:/temp/subdirectory/AcSpecfc.dll size: 474.112 kilobytes
C:/temp/subdirectory/AcXtrnal.dll size: 211.968 kilobytes
C:/temp/subdirectory/apihex86.dll size: 41.984 kilobytes
C:/temp/subdirectory/drvmain.sdb size: 151.136 kilobytes
C:/temp/subdirectory/msimain.sdb size: 1757.98 kilobytes
C:/temp/subdirectory/pcamain.sdb size: 37.358 kilobytes
C:/temp/subdirectory/sysmain.sdb size: 3932.71 kilobytes

… next we will explore the QObject … the mother of all Qt widgets.