Illustrates all of the basic parts of a class, e.g., Constructors, operators, destructor, and member data.
/////////////////////////////////////////////////////////////////////////////
// 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");
}