/*-------------------------------------------------------------------
Demonstration library types std::string and std::vector<T>
*/
void demo_stdlib() {
print("Demonstrate C++ Objects\n");
showNote("std library types string and vector<T>");
/* create and display std::string object */
auto str = std::string("\"Wile E. Coyote\"");
auto out = std::string("contents of str = ") + str;
print(out);
print("--- showType(str, \"str\"); ---");
showType(str, "str", nl);
/* create and display std::vector<double> */
auto vec = std::vector<double>{ 3.5, 3, 2.5, 2 };
showOp("showType(vec, \"vec\");");
showType(vec, "vec");
std::cout << "\n vec:" << vec;
// equivalent to:
// operator<<(operator<<(std::cout, "\n vec:"), vec);
// uncomment the preceeding line to see the output repeated
showOp("vec[2] = -2.5;");
vec[2] = -2.5;
std::cout << "\n vec:" << vec;
showOp("auto vec2 = vec : copy construction");
/* copy construction */
auto vec2 = vec;
std::cout << "\n vec2:" << vec2;
showOp("vec2[0] = 42;");
vec2[0] = 42;
std::cout << "\n vec2: " << vec2;
std::cout << "\n vec: " << vec;
showNote(
"Copy construction, auto vec2 = vec, creates\n "
"independent instance. So changing target vec2\n "
"has no affect on source vec."
);
showOp("vec = vec2 : copy assignment");
vec = vec2;
// equivalent to:
// vec.operator=(vec2);
// uncomment the preceeding line and observe no change
std::cout << "\n vec: " << vec << "\n";
Demonstrate C++ Objects
--------------------------------------------------
std library types string and vector<T>
--------------------------------------------------
contents of str = "Wile E. Coyote"
--- showType(str, "str"); ---
str type: class std::basic_string<char,struct std:...
size: 40
vector<T>: {
3.5, 3, 2.5, 2
}
--- showType(vec, "vec"); ---
vec type: class std::vector<double,class std::allo...
size: 32
--- vec[2] = -2.5; ---
vec:
vector<T>: {
3.5, 3, -2.5, 2
}
--- auto vec2 = vec : copy construction ---
vec2:
vector<T>: {
3.5, 3, -2.5, 2
}
--- vec2[0] = 42; ---
vec2:
vector<T>: {
42, 3, -2.5, 2
}
vec:
vector<T>: {
3.5, 3, -2.5, 2
}
--------------------------------------------------
Copy construction, auto vec2 = vec, creates
independent instance. So changing target vec2
has no affect on source vec.
--------------------------------------------------
--- vec = vec2 : copy assignment ---
vec: [42, 3, -2.5, 2]
/*---------------------------------------------------------
Points.h defines a space-time point class:
- Point4D represents points with three double spatial
coordinates and std::time_t time coordinate.
*/
#pragma warning(disable:4996) // warning about ctime use
#include <iostream>
#include <vector>
#include <chrono>
#include <ctime>
/*---------------------------------------------------------
Point4D class represents a point in a 4-Dimensional
space-time lattice. Simple enough for illustration,
but still useful.
It declares all of the special class methods, most with
default qualifiers to indicate that the compiler will
generate them as needed.
The word ctor is an abbreviation of constructor and dtor
an abbreviation for destructor.
*/
class Point4D {
public:
Point4D(); // void ctor
Point4D(const Point4D& pt) = default; // copy ctor
Point4D(Point4D&& pt) = default; // move ctor
Point4D& operator=(const Point4D& pt) = default;
// copy assignment
Point4D& operator=(Point4D&& pt) = default;
// move assignment
~Point4D() = default; // dtor
std::string timeToString();
void updateTime();
void show();
double& xCoor() { return x; }
double& yCoor() { return y; }
double& zCoor() { return z; }
std::time_t& tCoor() { return t; }
private:
double x;
double y;
double z;
std::time_t t;
};
Point4D::Point4D() {
x = y = z = 0.0;
t = std::time(0);
}
std::string Point4D::timeToString() {
return ctime(&t);
/*
ctime is depricated due to a thread-safety issue.
That's not a problem here. Compiler warning
recommends converting to ctime_s, which, unfortunately
has a different and awkward interface.
*/
}
void Point4D::updateTime() {
t = std::time(0);
}
void Point4D::show() {
std::cout << "\n " << "Point4D {";
std::cout << "\n "
<< x << ", " << y << ", " << z << ", ";
std::cout << "\n " << timeToString();
std::cout << " }";
}
/* required for showType(T t, const std::string& nm) */
std::ostream& operator<<(
std::ostream& out, Point4D& t1
) {
out << "Point4D {";
out << " " << t1.xCoor() << ", " << t1.yCoor() << ", "
<< t1.zCoor() << std::endl
<< " " << t1.timeToString() << std::endl
<< " }" << std::endl;
return out;
}
/*------------------------------------------------*/
showNote("user-defined type Point4D");
Point4D p1;
p1.show();
p1.xCoor() = 42;
p1.zCoor() = -3.5;
/*- t contains time of construction -*/
p1.show();
print();
print("--- showType(p1, \"p1\", nl) ---");
showType(p1, "p1", nl);
std::cout << " p1.xCoor() returns value "
<< p1.xCoor() << "\n";
showOp("Point4D p2 = p1 : copy construction");
Point4D p2 = p1; // copy construction
p2.show();
showOp("p2.xCoor() *= 2");
p2.xCoor() *= 2;
p2.show();
showOp("p1 = p2 : copy assignment");
p1 = p2; // copy assignment
p1.show();
--------------------------------------------------
user-defined type Point4D
--------------------------------------------------
Point4D {
0, 0, 0,
Mon May 1 16:04:27 2023
}
Point4D {
42, 0, -3.5,
Mon May 1 16:04:27 2023
}
--- showType(p1, "p1", nl) ---
p1 type: class Point4D
size: 32
p1.xCoor() returns value 42
--- Point4D p2 = p1 : copy construction---
Point4D {
42, 0, -3.5,
Thu Dec 7 19:34:59 2023
}
--- p2.xCoor() *= 2 ---
Point4D {
84, 0, -3.5,
Thu Dec 7 19:34:59 2023
}
--- p1 = p2 : copy assignment ---
Point4D {
84, 0, -3.5,
Thu Dec 7 19:34:59 2023
}
/*------------------------------------------------*/
showNote("heap-based string instance");
/* standard library type std::string */
/* uses alias pU for std::unique_ptr */
showOp(
"pU<std::string> "
"pStr(new std::string(\"\\\"Road Runner\\\"\")"
);
pU<std::string> pStr(
new std::string("\"Road Runner\"")
);
std::cout << "\n pStr contents = "
<< *pStr << "\n";
showOp("showType(*pStr, \"*pStr\")");
showType(*pStr, "*pStr", nl);
/* std::unique_ptr<T> cannot be copied
but can be moved */
showOp("showType(move(pStr), \"pStr\")");
showType(move(pStr), "pStr", nl);
// showType(pStr, "pStr") is an illegal call
// since pStr cannot be copied to preserve uniqueness
--------------------------------------------------
heap-based string instance
--------------------------------------------------
--- pU<std::string> pStr(new std::string("\"Road Runner\"") ---
pStr contents = "Road Runner"
--- showType(*pStr, "*pStr") ---
*pStr type: class std::basic_string<char,struct std:...
size: 40
--- showType(move(pStr), "pStr") ---
pStr type: class std::unique_ptr<class std::basic_s...
size: 8
/*------------------------------------------------*/
/* standard library type std::vector<T> */
showNote("heap-based vector instance");
showOp(
"pU<std::vector<double>>\n "
" pVec(
new std::vector<double>{ 1.5, 2.5, 3.5 }
);"
);
pU<std::vector<double>> pVec(
new std::vector<double>{ 1.5, 2.5, 3.5 }
);
std::cout << "\n *pVec = " << *pVec;
showType(*pVec, "*pVec", nl);
std::cout << "\n pVec = " << pVec;
showType(move(pVec), "move(pVec)", nl);
--------------------------------------------------
heap-based vector instance
--------------------------------------------------
--- pU<std::vector<double>>
pVec(new std::vector<double>{ 1.5, 2.5, 3.5 }); ---
*pVec =
vector<T>: {
1.5, 2.5, 3.5
}
*pVec type: class std::vector<double,class std::allo...
size: 32
pVec = 000002897B682AC0
move(pVec) type: class std::unique_ptr<class std::vector<...
size: 8
/*------------------------------------------------*/
/* custom point types */
showNote("heap-based Point4D instance");
showOp("pU<Point4D> pPoint4D(new Point4D())");
pU<Point4D> pPoint4D(new Point4D());
pPoint4D->show();
pPoint4D->xCoor() = 1;
pPoint4D->yCoor() = 2;
pPoint4D->zCoor() = -3;
pPoint4D->updateTime();
pPoint4D->show();
std::cout << "\n pPoint4D->zCoor() = "
<< pPoint4D->zCoor();
showOp("showType(*pPoint4D, \"*pPoint4D\");");
showType(*pPoint4D, "*pPoint4D");
showOp(
"showType(std::move(pPoint4D), \"pPoint4D\");"
);
showType(std::move(pPoint4D), "pPoint4D", nl);
/* pPoint4D moved, so now invalid */
print("\n That's all Folks!\n\n");
}
--------------------------------------------------
heap-based Point4D instance
--------------------------------------------------
--- pU<Point4D> pPoint4D(new Point4D()) ---
Point4D {
0, 0, 0,
Mon May 1 16:04:27 2023
}
Point4D {
1, 2, -3,
Mon May 1 16:04:27 2023
}
pPoint4D->zCoor() = -3
--- showType(*pPoint4D, "*pPoint4D"); ---
*pPoint4D type: class Point4D
size: 32
--- showType(std::move(pPoint4D), "pPoint4D"); ---
pPoint4D type: class std::unique_ptr<class Point4D,stru...
size: 8
That's all Folks!
/*---------------------------------------------------------
AnalysisObj.h
- Provides functions that analyze types, display results
and other program defined information.
- Some of this code requires complex template operations.
Those will be discussed in the generics bit.
- You can skip the hard parts until then, without loss
of understanding.
*/
#include <typeinfo> // typeid
#include <utility> // move()
#include <sstream> // stringstream
#include <type_traits> // is_scalar, if constexpr
#include <iostream> // cout
#include <vector> // vector
/*---------------------------------------------------------
Display and Analysis function and globals definitions
-----------------------------------------------------------
*/
const std::string nl = "\n";
/*---------------------------------------------------------
Mutable globals are a common source of bugs. We try not
to use them, but will use DisplayParams here to control
how insertion operator sends instances to std output.
Only the trunc variable is used in this demo. The others
will be used in the Bits_GenericCpp demo.
*/
struct displayParams {
size_t left = 2; // number of spaces to indent
size_t width = 7; // width of display row
size_t trunc = 40; // replace text after trunc with ...
} DisplayParams; // global object
/*-----------------------------------------------
Display text after newline and indentation
*/
inline void print(const std::string& txt = "") {
std::cout << "\n " << txt;
}
/*-----------------------------------------------
Display text after newline and indentation
- provides trailing newline
*/
inline void println(const std::string& txt = "") {
std::cout << "\n " << txt << "\n";
}
/*-----------------------------------------------
Overload operator<< required for
showType(std::vector<T> v, const std::vector<T>& nm)
*/
template<typename T>
std::ostream& operator<< (
std::ostream& out, const std::vector<T>& vec
) {
out << "[";
for (auto it = vec.begin(); it != vec.end(); ++it)
{
out << *it;
if (it != vec.end() - 1)
out << ", ";
}
out << "]";
return out;
}
/*-----------------------------------------------
Display emphasized text
*/
inline void showNote(
const std::string& txt, const std::string& suffix = ""
) {
print("--------------------------------------------------");
print(" " + txt);
print("--------------------------------------------------");
std::cout << suffix;
}
/*-----------------------------------------------
Display emphasized line
*/
inline void showOp(
const std::string& opstr, const std::string& suffix = ""
) {
std::cout << "\n --- " << opstr << " ---" << suffix;
}
/*-----------------------------------------------
Helper function for formatting output
- truncates line to N chars and adds ellipsis
*/
inline std::string truncate(size_t N, const char* pStr) {
std::string temp(pStr);
if(temp.length() > N) {
temp.resize(N);
return temp + "...";
}
return temp;
}
/*-----------------------------------------------
Helper function for formatting output
- generates string of n blanks to offset text
*/
inline std::string indent(size_t n) {
return std::string(n, ' ');
}
/*-----------------------------------------------
Display calling name, static class, and size
*/
template<typename T>
void showType(
T t, const std::string &callname,
const std::string& suffix = ""
) {
std::cout << "\n " << callname; // show name at call site
std::cout << " type: "
<< truncate(DisplayParams.trunc,typeid(t).name());
std::cout << "\n size: " << sizeof(t); // show size on stack
std::cout << suffix;
}
/*-----------------------------------------------
Format output for scalar types like primitives
*/
template<typename T>
std::string formatScalar(
const T& t, const std::string& nm,
const std::string& suffix = "",
size_t left = 2
) {
std::stringstream out;
out << "\n" << indent(left) << nm << ": " << t << suffix;
return out.str();
}
/*-----------------------------------------------
Format output for strings
- indent and embed in quotation marks
*/
template<typename T>
std::string formatString(
const T& t, const std::string& nm,
const std::string& suffix = "",
size_t left = 2
) {
std::stringstream out;
out << "\n" << indent(left) << nm
<< ": \"" << t << "\"" << suffix;
return out.str();
}
/*-------------------------------------------------------------------
Cpp_Objects.cpp
- depends on Points.h to provide user-defined point class
- depends on Analysis.h for several display and analysis functions
*/
#include <iostream> // std::cout
#include <memory> // std::unique_ptr
#include <vector> // vector<T> class
#include <array> // array<T> class
#include <map> // map<K,V> class
#include <set> // set<T> class
#include "AnalysisObj.h" // Analysis functions for this demo
#include "PointsObj.h" // Point4D class declaration
/*-----------------------------------------------
Note:
Find all Bits code, including this in
https://github.com/JimFawcett/Bits
You can clone the repo from this link.
-----------------------------------------------*/
/*
This demo uses the std::string and std::vector<T> classes
and a user defined class, Point4D, to illustrate how objects
are defined and instantiated.
Operations:
All the classes discussed here provide operations for:
T t2 = t1 // copy construction
T t3 = temporary // move construction
t1 = t2 // copy assignment
t3 = temporary // move assignment
All instances return their resources when they go out of
scope by implicitly calling their destructor.
Primitive types can all be copied.
Most library and user-defined types can be copied, moved,
and deleted by providing member constructors and destructor.
Often compiler generation works well, but for classes with
pointer members developers must provide those methods.
Processing:
All types are static, operations run as native code, and no
garbage collection is needed. Resources are returned at end
of their declaration scope.
*/
void demo_stdlib() { /*-- code elided --*/ }
void demo_Point4D() { /*-- code elided --*/ }
void demo_heap_string() { /*-- code elided --*/ }
void demo_heap_vector() { /*-- code elided --*/ }
void demo_heap_Point4D() { /*-- code elided --*/ }
int main() {
print("Demonstrate C++ Objects\n");
demo_stdlib();
demo_Point4D();
demo_heap_string();
demo_heap_vector();
demo_heap_Point4D();
print("\n That's all Folks!\n\n");
}
C:\github\JimFawcett\Bits\Cpp\Cpp_Objects\build > cmake .. -- Building for: Visual Studio 17 2022 -- Selecting Windows SDK version 10.0.22000.0 to target Windows 10.0.22621. -- The C compiler identification is MSVC 19.34.31942.0 -- The CXX compiler identification is MSVC 19.34.31942.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.34.31933/bin/Hostx64/x64/cl.exe - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.34.31933/bin/Hostx64/x64/cl.exe - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: C:/github/JimFawcett/Bits/Cpp/Cpp_Objects/build C:\github\JimFawcett\Bits\Cpp\Cpp_Objects\build > cmake --build . MSBuild version 17.4.1+9a89d02ff for .NET Framework Checking Build System Building Custom Rule C:/github/JimFawcett/Bits/Cpp/Cpp_Obje cts/CMakeLists.txt Bits_Objects.cpp Cpp_Objects.vcxproj -> C:\github\JimFawcett\Bits\Cpp\Cpp_Ob jects\build\Debug\Cpp_Objects.exe Building Custom Rule C:/github/JimFawcett/Bits/Cpp/Cpp_Obje cts/CMakeLists.txt C:\github\JimFawcett\Bits\Cpp\Cpp_Objects\build >
| Reference | Description |
|---|---|
| C++ Story | E-book with thirteen chapters covering most of intermediate C++ |
| C++ Bites | Relatively short feature discussions |
| STRCode | User-defined string type with all standard methods and functions documented with: purpose, declaration, definition, invocation, and notes. |
| w3schools tutorial | Slow and easy walk throught basics. |
| cppreference.com | Very complete reference with lots of details and examples. |
Point4d:
something was at that point.
trajectory of an aircraft or a machine tool cutting edge.
⇐ C++ class syntax:
and destruction, all based on class name. They are illustrated
in this block.
destructor, and assignment operator if using code implies a
copy and/or assignment and the class designer has not provided
them. Destructors are always required and are generated if
the class does not provide one.
construction, assignment, and destruction operations for all parts
of the class. These operations are applied member-wise, e.g.,
to each base class and member datum, in order of their declaration.
members and bases have correct copy, destruction, and assignment
semantics.
"default" qualifier to indicate that the designer expects the
generated methods will be correct. Use the "delete" qualifier to
prevent the compiler from generating the deleted operation.
Function overloading:
Essentially a function overload is a new function with a name based
on the original function name and the types of its arguments
created, by a process call "name-mangling".
of the void constructor, Point4D(), and the copy and move
assignment operators are overloads of the operator= function.
⇐ C++ operators
are functions that are called when statements with operator symbolsare encountered, e.g.,
objects of type
process. The overload for Point4D is needed by functions in the
AnalysisObjects.h library.