S R T B H P N

ClassAnatomy.h, ClassAnatomy.cpp, ClassAnatomy.txt, Classes webpage

Illustrates all of the basic parts of a class, e.g., Constructors, operators, destructor, and member data.

ClassAnatomy.cpp

/////////////////////////////////////////////////////////////////////////////
// TestClass.cpp - Implemented to demonstrate class operations             //
//                                                                         //
// Application:  CSE687 - OOD demonstration, Fall 2018                     //
// Platform:     Dell XPS 8920, Win 10 Pro, Visual Studio 2017             //
// Author:       Jim Fawcett, Syracuse University, CST 4-187               //
//               jfawcett@twcny.rr.com, http://ecs.syr.edu/faculty/fawcett //
/////////////////////////////////////////////////////////////////////////////

#include "TestClass.h"
#include "..\Helpers\Helpers.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <memory>

// add this to stringUtiltities

//----< remove a substring if it exists, returning by value >----------------

std::string remove(std::string& src, const std::string& removed)
{
  std::string modified = src;
  size_t pos = modified.find(removed);
  if (pos >= modified.size())
    return modified;
  std::string ret = modified.erase(pos, removed.size());
  return ret;
}
//----< remove a substring if it exists, returning by reference >------------

void inPlaceRemove(std::string& src, const std::string& removed)
{
  size_t pos = src.find(removed);
  if (pos >= src.size())
    return;
  src = src.erase(pos, removed.size());
}
//----< configure output lines into fixed size fields >----------------------

void showLine(const std::string& msg, size_t line, const std::string& function)
{
  std::ostringstream lineStr, funcStr;
  lineStr << line;
  funcStr << function;
  std::string fStr = funcStr.str();
  inPlaceRemove(fStr, "__thiscall ");  // remove VSC++ compiler decorations
  inPlaceRemove(fStr, "__cdecl ");     // as not relevant for this discussion
  std::cout << "\n  " << std::setw(40) << std::left << msg.substr(0, 40);
  std::cout << std::setw(9) << " at line " << std::setw(5) << std::right << "#" + lineStr.str() + " ";
  std::cout << std::left << fStr.substr(0, 60);
}

//----< default constructor >----------------------------------------------

Test::Test()
{
  showLine("void construction of Test",__LINE__, __FUNCSIG__);
  name_ = "unnamed";
}
//----< promotion constructor >--------------------------------------------

Test::Test(const std::string& name) : name_(name)
{
  std::string msg = "named construction of " + name;
  showLine(msg, __LINE__, __FUNCSIG__);
}
//----< copy constructor >-------------------------------------------------

Test::Test(const Test& t) : name_(t.name_)
{
  std::string msg = "copy of " + name_;
  showLine(msg, __LINE__, __FUNCSIG__);
}
//----< move constructor >-------------------------------------------------

Test::Test(Test&& t) : name_(std::move(t.name_))
{
  std::string msg = "move of " + name_;
  showLine(msg, __LINE__, __FUNCSIG__);
}
//----< copy assignment operator >-----------------------------------------

Test& Test::operator=(const Test& t)
{
  if (this == &t)
    return *this;
  name_ = t.name_;
  std::string msg = "copy assignment of " + name_;
  showLine(msg, __LINE__, __FUNCSIG__);
  return *this;
}
//----< move assignment operator >-----------------------------------------

Test& Test::operator=(Test&& t)
{
  if (this == &t)
    return *this;
  name_ = std::move(t.name_);
  std::string msg = "move assignment of " + name_;
  showLine(msg, __LINE__, __FUNCSIG__);
  return *this;
}
//----< destructor >-------------------------------------------------------

Test::~Test()
{
  std::string msg = "destruction of " + name_;
  showLine(msg, __LINE__, __FUNCSIG__);
}
//----< name "property" >--------------------------------------------------

std::string& Test::name()
{
  return name_;
}
//----< enunciator >-------------------------------------------------------

void Test::say()
{
  std::cout << "\n  my name is " << name_;
}
//----< cosmetic object that emits line feeds on termination >-------------

struct lineFeeds
{
  ~lineFeeds()
  {
    std::cout << "\n\n";
  }
} cosmetic;
//----< demonstration of move construction >-------------------------------

Test demoFunc()
{
  Test demo("function demo's temporary Test");
  showLine(demo.name(), __LINE__, __FUNCSIG__);
  return demo;
}
//----< test stub >--------------------------------------------------------

#include <stdexcept>

int main()
{
  using Helper = UtilityHelpers::Utilities;
  Helper::title("Demonstrate Test Class");

  showLine("-- promotion construction of Test Fred", __LINE__, __FUNCSIG__);
  Test t("Fred");         // named construction

  showLine("-- copy construction of Test Fred", __LINE__, __FUNCSIG__);
  Test t1 = t;            // copy construction

  showLine("-- call demoFunc()", __LINE__, __FUNCSIG__);
  Test t2 = demoFunc();   // move construction

  showLine("-- void construction of unnamed Test", __LINE__, __FUNCSIG__);
  Test t3;

  showLine("-- assignment of Test Fred", __LINE__, __FUNCSIG__);
  t3 = t1;                // copy assignment

  showLine("-- assignment of temporary test", __LINE__, __FUNCSIG__);
  t3 = Test();            // move assignment from temporary

  std::cout << "\n";

  t1.name() = "t1";
  t2.name() = "t2";
  t3.name() = "t3";

  Helper::title("Creating initialized std::vector of Tests");

  showLine("-- initialize vector with copies of t1 & t2, and move of t3", __LINE__, __FUNCSIG__);
  std::vector<Test> vt{ t1, t2, std::move(t3) };

  for (auto& e : vt)
  {
    e.say();
  }
  std::cout << "\n";

  Helper::title("Testing push_backs");

  showLine("-- promotion construction of t4", __LINE__, __FUNCSIG__);
  Test t4("t4");

  showLine("-- promotion construction of t5", __LINE__, __FUNCSIG__);
  Test t5("t5");

  showLine("-- push_back of t4", __LINE__, __FUNCSIG__);
  vt.push_back(t4);

  showLine("-- push_back of std::move(t5)", __LINE__, __FUNCSIG__);
  vt.push_back(std::move(t5));

  for (auto& e : vt)
  {
    e.say();
  }
  std::cout << "\n";

  Helper::title("Creating vector of smart pointers");
  /*
   *  - unique_ptr<T> is a smart pointer to an instance t of type T
   *  - it assumes it is the only reference to t and that t is stored on the native heap
   *  - since it represents unique ownership, it cannot be copied or assigned, only moved
   *  - when it goes out of scope, either through a normal exit from the scope where it was defined
   *    or because an exception was thrown, it calls delete on its iternal pointer to t
   */

  showLine("-- attach unique_ptr sp1 to new Test t6", __LINE__, __FUNCSIG__);
  std::unique_ptr<Test> sp1(new Test("t6"));

  showLine("-- attach unique_ptr sp2 to new Test t7", __LINE__, __FUNCSIG__);
  std::unique_ptr<Test> sp2(new Test("t7"));

  showLine("-- create vector of these unique_ptrs", __LINE__, __FUNCSIG__);
  std::vector<std::unique_ptr<Test>> vp;

  showLine("-- push_back std::move(sp1)", __LINE__, __FUNCSIG__);
  vp.push_back(std::move(sp1));

  showLine("-- push_back std::move(sp2)", __LINE__, __FUNCSIG__);
  vp.push_back(std::move(sp2));

  ///////////////////////////////////////////////////////////////////////////
  // The line below doesn't work.  Initializer_lists are constant so
  // you can copy but can't move out of them.  Unique_ptr is moveable but
  // not copyable so you have to use push_back
  //
  //  std::vector<std::unique_ptr<Test>> vp { std::move(sp1), std::move(sp2) };
  ///////////////////////////////////////////////////////////////////////////

  // Resetting sp2 does not reset the vector vp's unique_ptr.
  // Instead, it is resetting the now invalid sp2 in main to a new valid Test instance, t8.

  showLine("-- reset sp2 to new Test(t8)", __LINE__, __FUNCSIG__);
  sp2.reset(new Test("t8"));  // re-initializes sp2 to point to t8, original object was moved into vector so nothing to delete

  showLine("-- reset sp2 to new Test(t9)", __LINE__, __FUNCSIG__);
  sp2.reset(new Test("t9"));  // re-initializes sp2 to point to t9 then deletes t8

  for (auto& p : vp)
  {
    p->say();
  }
  std::cout << "\n";

  Helper::title("Done with testing");
}