He, Peng

A Roboticist.

The secret of getting ahead is getting started.


Some Basic Notations On Re-Learning C++

Abstract: Recently I start using C++ again but having a long time in Python makes me almost forget everything on C++, in which case is common. This programming language is not a big deal, what matters are the logistics behind your programming thoughts. This post is where I collect my old coding snippets when learning C++. Hope these are good to you as well !

Tips

  1. Primary operators(name(),[],->,.), left to right rule.
  2. Unary operators(++,—,~,*,&,sizeof) are in same order, follow right to left rule. For instance:

    • *b++ : after all expressions increase the pointer by one, take b value,
    • (*b)++ : take b value and increase it by one.
    • *++b : increase the pointer by one and take the value

Important Filing Ideas

Header file: The definitions of macros, classes, structures, unions, and inline functions, as well as external data declarations, function prototypes, and typedefs. It is acceptable to place all common #include directives in a common header file and include it instead.

For a large project the cpp files should be placed in a folder named src and the hpp files should be put in a folder called include. When deeper category is asked, you should orgnized the files in their category name folders, such that:
test/include/handler/HandlerTest.hpp and test/src/[handler/]HandlerTest.cpp are exist. When you use #include "handler/HandlerTest.hpp" this will by default search under the include folder.

For example, This is called definitions of a class:

namespace PHE {  
    class ArrayList
    {
    public:
        ArrayList();
        ~ArrayList();
        string merge(string words, string more);
    private:

    };
}

And This is called declarations of a class and should NOT be placed in a header file

PHE::ArrayList::ArrayList(){};  
PHE::ArrayList::~ArrayList(){};

string  
PHE::ArrayList::merge(string word, string more)  
{
    string sentence;
    sentence.append(word);
    sentence.append(more);

    return sentence;
}

Don’t mess them up !

Naming Conventions

  • Function and function-like macro names should be verbs; all other names should be nouns.
  • Object-like macro, const-qualified variable, and typedef names should be in upper case.
  • Function, function-like macro, and class/struct/union/enum tag names should be in Pascal case (i.e., PascalCaseName).
  • All other names should be in camel case, (i.e., camelCaseName).

Programming Shorthands

Good Return code

#include <cstdlib>

int main()  
{
     return(EXIT_SUCCESS); 
     // or return(EXIT_FAILURE);
}

Create a typed instance with pointer: Queue<int> *pQ = new Queue<int>();

Open File Examples C Version

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 * Open the file named in <fileName> and return its FILE pointer if the
 * open succeeds.  If it fails display an error message and terminate
 * the program with an error code.
 */
FILE *OpenFile(const char *fileName)  
{
    FILE *fp;
    /* Open the file in the read-only mode & check for failure. */
    if ((fp = fopen(fileName, "r")) == NULL)
    {
        /* Display an error message and terminate with an error exit code. */
        fprintf(stderr, "File %s didn't open.\n", fileName);
        perror(fileName);
        exit(EXIT_FAILURE);
    }
    return fp;
}

Open File Examples C++ Version

#include <cstdlib>
#include <fstream>
#include <iostream>
//
// Open the file named in <fileName> using the object referenced by
// <inFile>. If it fails display an error message and terminate the
// program with an error code.
//
void OpenFile(const char *fileName, std::ifstream &inFile)  
{
    // Open file for read only.
    inFile.open(fileName);
    // If open fails print an error message and terminate with an error code.
    if (!inFile.is_open())
    {
        std::cerr << "File " << fileName << " didn't open.\n";
        std::exit(EXIT_FAILURE);
    }
}

Miscellaneous Topics

Literals & Magic Number

For C Style: #define DIAGONAL '.'
For C++ Style: const char LEADER = '#';

Functions

In multi-file programs all functions not shared with other files should be declared static to limit their scope.

External Variables

Referencing declarations of external variables used by more than one file must be kept in header files that are included by any files needing them. Do not by duplicate the declaration in each file. In multi-file programs, all external variables not shared with other files should be declared static to limit their scope.


Example: Basic Struct Uses

Pass Pointer back from a function and define incoming pointer parameters as constants

// Define structure type to represent a time.
struct MyTime { int hours, minutes, seconds; };

//
// Determine the amount of time elapsed between the times stored in the
// MyTime structures in <time1> and <time2> (starting with the time in
// <time1>) and store the result in MyTime structure <elapsed>. If
// the time in <time1> is greater than the time in <time2> the time
// in <time2> is considered to be in the next day. Return a pointer
// to <elapsed>.
//
MyTime *DetermineElapsedTime(const MyTime *time1, const MyTime *time2)  
{
     static MyTime elapsed;

     return(&elapsed);
}

Define a constant array with struct  
struct Month  
{
    const char *pName;
    const int days;
};

const Month MONTHS[] = {  
    { "November", 30 },
    { "December", 31 }
};

To use this, the string compare requires pointer:

int i;  
for (i = 0; i < MAX_MONTH; ++i)  
{
     if (strcmp(pMonthName, MONTHS[i].pName) == 0) break;
}

Const function if no inputs  
int RayMitchell::Date::getYear() const  
{
    return year;
}

Example: Call A Static Function Of A Class

Class Definition with “static” key word, this is in a header file

namespace RayMitchell  
{
    class SavingsAccount
    {
    public:
        // Constructors
        SavingsAccount(double initialBalance);

        // Accessors / mutators
        double getSavingsBalance() const;

        // Apply monthly interest to current balance
        void calculateMonthlyInterest();

        // Change the interest rate (applies to all SavingsAccounts)
        static void modifyInterestRate(double newInterestRate);

    private:
        // Current balance for this account
        double savingsBalance;

        // The interest rate (applies to all SavingsAccounts)
        static double annualInterestRate;
    };
}

Class Declaration in cpp file

// Static data members must be defined in a translation unit (initialized to
// 0 automatically)
double RayMitchell::SavingsAccount::annualInterestRate;

// no need to put "static" again in front of the function name
void RayMitchell::SavingsAccount::modifyInterestRate(double newInterestRate)  
{
    if (newInterestRate < 0) {
        cerr << "Illegal interest rate " << newInterestRate
            << "; must be greater than zero.  Setting to 0%\n";
        SavingsAccount::annualInterestRate = 0;
    }
    else {
        SavingsAccount::annualInterestRate = newInterestRate;
    }
}

Call static function without an instance

int main()  
{
    // Set interest rate for first month
    cout << "Setting interest rate to " << MONTH_1_INTEREST_RATE << "\n";
    SavingsAccount::modifyInterestRate(MONTH_1_INTEREST_RATE);
}

Example: Formatting Input Into Struct

Partially declare struct member after definition and allocate it later on.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LUNCH_ITEMS 5  /* total lunch menu items */
#define FIXED_ITEMS 2  /* items initialized when declared */
#define BUFSIZE 256    /* size of input buffer */
#define BUFFMT "%255"  /* scanf field width for buffer */

/*
 * Prompt the user to input information about some food items and store them
 * in structures in an array that already has some hard-coded food item
 * information stored in it.  The food name strings occupy only exactly the
 * amount of memory necessary to hold them (including the null terminator
 * charactor). After the food item information has been input and stored
 * all food item information in the array is displayed and all dynamically-
 * allocated memory is freed.
 */
int main(void)  
{
    int foodItemNo;

    /*
     * Define type struct Food, declare an array of struct Food objects, and
     * partially initialize the array.
     */
    struct Food
    {
        char *name;
        int weight, calories;
    } lunch[LUNCH_ITEMS] = {{"apple", 4, 100}, {"salad", 2, 80}};

    /*
     * Since members of the remaining structures have not been explicitly * initialized, each name member is a null pointer. Each must, thus,
     * be initialized to point to an area of storage where the incoming
     * characters of the food name can be stored.
     */
    for (foodItemNo = FIXED_ITEMS; foodItemNo < LUNCH_ITEMS; ++foodItemNo)
    {
        size_t length;
        char buf[BUFSIZE];                  /* for getting name of food */

        printf("Enter:   food  weight  calories     ");
        scanf(BUFFMT "s %i %i", buf, &lunch[foodItemNo].weight, &lunch[foodItemNo].calories);
        length = strlen(buf) + 1;           /* characters used in buf + '\0' */

        /* allocate storage for the name pointer to point to */
        if ((lunch[foodItemNo].name = (char *)malloc(length)) == NULL)
        {
            fprintf(stderr, "malloc out of memory\n");
            exit(EXIT_FAILURE);
        }
        /* copy food into malloc buffer */
        memcpy(lunch[foodItemNo].name, buf, length);
    }

    printf("\tLUNCH MENU\nITEM\tWEIGHT\tCALORIES\n");
    for (foodItemNo = 0; foodItemNo < LUNCH_ITEMS; foodItemNo++)
    {
        printf("%s\t%i\t%i\n", lunch[foodItemNo].name,
               lunch[foodItemNo].weight, lunch[foodItemNo].calories);
        if (foodItemNo >= FIXED_ITEMS)
            free(lunch[foodItemNo].name);
    }
    return(EXIT_SUCCESS);
}

Example: Operator Overloading and "Friend" Keyword

A friend function of a class is defined outside that class' scope but it has the right to access all private and protected members of the class. Even though the prototypes for friend functions appear in the class definition, friends are not member functions.

In Header File:

#include <iostream>
using std::istream;  
using std::ostream;

namespace RayMitchell  
{
    class Complex
    {
        // Friend operators
        friend istream &operator>>(istream &in, Complex &destination);
        friend ostream &operator<<(ostream &out, const Complex &source);

    public:
        // Constructors
        Complex(double real = 0.0, double imaginary = 0.0);

        // Operators
        Complex operator+(const Complex &other) const;
        bool operator!=(const Complex &other) const;

    private:
        double real;
        double imaginary;
    };

    // Forward declarations
    istream &operator>>(istream &in, Complex &destination);
    ostream &operator<<(ostream &out, const Complex &source);
}

In CPP File: Fast construction

RayMitchell::Complex::Complex(double real, double imaginary)  
    : real(real), imaginary(imaginary)
{
    // Do nothing
}

istream & RayMitchell::operator>>(istream &in, Complex &destination)  
{
    // Read in format "a + bi"
    char op, i;
    in >> destination.real >> op >> destination.imaginary >> i;
    if (op == '-')
        destination.imaginary = -destination.imaginary;
    return in;
}

ostream & RayMitchell::operator<<(ostream &out, const Complex &source)  
{
    return out << source.real << (source.imaginary >= 0 ? "+" : "")
        << source.imaginary << "i";
}

RayMitchell::Complex RayMitchell::Complex::operator+(const Complex &other) const  
{
    // (a + bi) + (c + di) = (a + c) + (b + d)i
    return Complex(real + other.real, imaginary + other.imaginary);
}

How to use the code:

int main()  
{
    Complex y(4.3, 8.2);

    // Test addition
    cout << "y + z: " << y << " + " << z << " = " << y + z << "\n";

    // Test stream insertion & extraction operators
    cout << "Enter a complex: ";
    cin >> x;
    cout << "You entered " << x << "\n";
}

Example: Inheritance and Virtual Function

Public Inheritance: When deriving a class from a public base class, public members of the base class become public members of the derived class and protected members of the base class become protected members of the derived class.

Protected Inheritance: When deriving from a protected base class, public and protected members of the base class become protectedmembers of the derived class.

Private Inheritance: When deriving from a private base class, public and protected members of the base class become privatemembers of the derived class

In Header File:

class Shape  
{
public:  
    // Virtual destructor (necessary to guarantee derived class destructor
    // called when dynamic object destroyed through base class pointer)
    virtual ~Shape() {}

    // Output the shape
    virtual void print() const = 0;
};

class TwoDimensionalShape : public Shape  
{
public:  
    // Return the two-dimensional shape's area
    virtual double getArea() const = 0;
};

class Circle : public TwoDimensionalShape  
{
public:  
    // Constructors
    Circle(double radius);

    virtual double getArea() const;
    virtual void print() const;

private:  
    double radius;
};

In CPP File:

RayMitchell::Circle::Circle(double radius)  
    : radius(radius)
{
}

double RayMitchell::Circle::getArea() const  
{
    // Area = PI * r ^ 2
    return PI * radius * radius;
}

void  
    RayMitchell::Circle::print() const
{
    cout << "Circle with radius " << radius
        << " has area " << getArea() << "\n";
}

In Main File:

#include <iostream>
using std::cout;

#include <vector>
using std::vector;

int main()  
{
    // Dynamically allocate one of each shape and store pointers in vector
    vector<Shape *> shapes;
    shapes.push_back(new Circle(2.0));
    shapes.push_back(new Cube(7.0));

    // Use RTTI to determine shape's type then output attributes based on type
    cout << "------------------------------------------------------\n";
    for (size_t i = 0; i < shapes.size(); ++i) {
        if (TwoDimensionalShape *p2D =
            dynamic_cast<TwoDimensionalShape *>(shapes[i])) {
                cout << "2D shape with area " << p2D->getArea() << "\n";
        }

        if (ThreeDimensionalShape *p3D =
            dynamic_cast<ThreeDimensionalShape *>(shapes[i])) {
                cout << "3D shape with surface area " << p3D->getArea()
                    << " and volume " << p3D->getVolume() << "\n";
        }
    }

    // Print attributes using base class virtual function
    cout << "-----------------------------------------------------------\n";
    for (size_t i = 0; i < shapes.size(); ++i) {
        shapes[i]->print();
    }

    // Free dynamically allocated shapes
    for (size_t i = 0; i < shapes.size(); ++i) {
        delete shapes[i];
    }
}

Example: Template and Typename. Exception-Safety

In Header File:

A template function or class can only be declared in header files

#include <algorithm>
#include <cassert>
#include <exception>
using namespace std;

namespace RayMitchell { namespace Homework2  
{
   //--------------------------------------------------------------------------
   // Helpers
   //--------------------------------------------------------------------------
   template <typename T>
   T *
   newCopy(const T *src,
           size_t srcsize,
           size_t destsize)
   {
      assert(destsize >= srcsize);

      T *dest = 0;
      if (destsize > 0)
      {
         dest = new T[destsize];
         if (src != 0 && srcsize != 0)
         {
            try
            {
               copy(src, src + srcsize, dest);
            }
            catch (...)
            {
               delete[] dest;             // This can't throw
               throw;                     // Rethrow original exception
            }
         }
      }
      return dest;
   }

   //--------------------------------------------------------------------------
   // Queue
   //--------------------------------------------------------------------------
   template <typename T>
   class Queue
   {
   public:
      Queue();                         // Construct empty queue
      ~Queue();                        // Destructor
      Queue(const Queue &);            // Copy constructor
      Queue &operator=(const Queue &); // Copy assignment operator
      void push(const T &);            // Add elem to back of queue
      void pop();                      // Remove front elem from queue
      T &front();                      // Return ref to front elem in queue
      const T &front() const;          // Return ref to front elem in queue
      bool empty() const;              // Return whether queue is empty
      size_t size() const;             // Return # of elems in queue

   private:
      T *v_;                           // Pointer to beginning of T buffer
      T *front_;                       // Pointer to first used T in buffer
      size_t vsize_;                   // # T's in buffer
      size_t vused_;                   // # used T's in buffer
   };

   template <typename T>
   Queue<T>::Queue()
      : v_(0),
        front_(0),
        vsize_(0),
        vused_(0)
   {}

   template <typename T>
   Queue<T>::~Queue()
   {
      delete[] v_;
   }

   template <typename T>
   Queue<T>::Queue(const Queue &other)
      : v_(newCopy(other.front_,
                   other.vused_,
                   other.vused_)),
        front_(v_),
        vsize_(other.vused_),
        vused_(other.vused_)
   {}

   template <typename T>
   Queue<T> &
   Queue<T>::operator=(const Queue &other)
   {
      if (this != &other)
      {
         T *v_new = newCopy(other.front_,
                            other.vused_,
                            other.vused_);
         delete[] v_;                  // This can't throw
         v_ = v_new;                   // Take ownership
         front_ = v_;
         vsize_ = other.vused_;
         vused_ = other.vused_;
      }
      return *this;
   }

   template <typename T>
   void
   Queue<T>::push(const T &t)
   {
      size_t vsize_new = vused_ + 1;
      T *v_new = newCopy(front_, vused_, vsize_new);
      try
      {
         v_new[vsize_new - 1] = t;     // Copy t into new buffer
      }
      catch (...)
      {
         delete[] v_new;               // This can't throw
         throw;                        // Rethrow original exception
      }
      delete[] v_;                     // This can't throw
      v_ = v_new;
      front_ = v_;
      vsize_ = vsize_new;
      ++vused_;
   }

   template <typename T>
   void
   Queue<T>::pop()
   {
      if (vused_ == 0)
      {
         throw logic_error("pop from empty Queue");
      }
      ++front_;
      --vused_;
   }

   template <typename T>
   T &
   Queue<T>::front()
   {
      if (vused_ == 0)
      {
         throw logic_error("front from empty Queue");
      }
      return *front_;
   }

   template <typename T>
   const T &
   Queue<T>::front() const
   {
      if (vused_ == 0)
      {
         throw logic_error("front from empty Queue");
      }
      return *front_;
   }

   template <typename T>
   bool
   Queue<T>::empty() const
   {
      return vused_ == 0;
   }

   template <typename T>
   size_t
   Queue<T>::size() const
   {
      return vused_;
   }
}
}
Recent Posts

Implementing Rapidly exploring Random Tree (RRT) OpenRave Plugin on A 7-DOF PR2 Robot Arm

Abstract: There are a lot motion planning algorithms but few of them work well on a high-dimensional…

In Study & Research, Projects, C++, RRT, OpenRaveRead More
Earlier Posts

Implementing A Star (A*) Path Planning Algorithm On A 3-DOF PR2 Robot In Python

Abstract: A Star Algorithm has been widely used in motion planning problems. This article will start…

In A*, Python, AStarRead More
comments powered by Disqus