about
Bits Objects C++
01/02/2024
0
Bits Repo Code Bits Repo Docs

Bits: C++ Objects

library and user-defined classes and objects

Synopsis:

This page demonstrates uses of C++ User-Defined types and their objects. The purpose is to quickly acquire some familiarity with user-defined types and their implementations.
  • C++ defines special class methods: copy and move constructors, copy and move assignment operators, and other operators for indexing and comparison etc.
  • The compiler will generate constructors and assignment operators if needed and not provided by the class. Those are correct if, and only if, the class's members and bases have correct semantics for those operations. For other cases, like pointer members, developers must either implement them or prohibit them. We will show how in this example.
  • Also, this is the first set of examples to partition code into several files. That supports readability, may improve translation times, and makes maintenance significantly easier.
C++ Aggregate Type Structure  
Aggregates are types whose instances hold instances of, or handles to, other types, i.e., an array can hold instances of an arbitrary type. Structs and classes can hold named instances or handles to arbitrary other types. There are three ways that happens:
  • Inheritance A C++ class can inherit multiple base class implementations. The memory footprint of this derived class contains the entire footprint of each of its bases.
  • Composition
    When an instance of a C++ type holds one or more instances of other types, the memory footprint of each composed type lies entirely within the memory footprint of its parent instance. We say the parent composes its child elements.
  • Aggregation
    C++ types can hold references and native pointers to instances in static, stack, or native heap memory, and smart pointer handles to instances of types stored in the native heap, e.g., std::unique_ptr<T> or std::shared_ptr<T>. When an instance of a type holds a pointer or handle to instances of other types, the parent's memory footprint holds only the pointer or handle, not the entire child instance. We say the parent aggregates the type referenced by the pointer or handle.
The freedom to structure classes in so many ways gives designers very powerful modeling tools at the expense of complexity and many paths to undefined behavior.
Demo Notes  
All of the languages covered in this demonstration support classes1. Each class provides a pattern for laying out a memory footprint and defines how data within are accessed. Three of the languages: C++, Rust, and C# provide generics. Each generic function or class is a pattern for defining functions and classes of a specific type. Thus a generic is a pattern for making patterns. The other two, Python and JavaScript, are dynamically typed and already support defining functions and classes that work for multiple types, e.g., no need for generics. This demonstration illustrates use of classes and objects, which for C++, Rust, and C#, are defined in a stackframe or in the heap or both. All data for Python and JavaScript are stored in managed heaps. A few functions in this code are generic, e.g., have type(s) to be specified by the caller at compile time. The next bit explores generics in greater detail with more discussion.

  1. Rust uses structs to implement objects in the same way that the other languages use classes. Here we will just use the term class for all of them.
The examples below show how to create and use instances of library and user defined types, with emphasis on illustrating syntax and basic operations.

1.0 Source Code

Code for this "Objects" Bit is presented in a six part sequence:
  1. Demonstrations of common std library types, showing both code and output.
  2. Code declaring a user-defined type, Point4D, is presented in the second block. Much of the technical weight of this Bit is carried by the left and right panels in this block.
  3. The third block illustrates how Point4D is created and used.
  4. Next, we show how to create instances of std library types and also Point4D in the native heap and how they are used.
  5. The next block presents code and discussion for a library of display and analysis functions.
  6. Finally, we illustrate the program structure for this demonstration. The emphasis here is on how functions and files partition processing for this demonstration.
The source code is available here. Download the entire Bits repository here.

1.1 Declaration and use of std::library types

This block presents creation and use of instances of std library types. It's provided here for comparison with the code for user-defined type Point4D. Here you see a side-by-side view of executable code with the output it provides. That proximity makes it easier to understand how the code works. Source code is available here. Download the entire Bits repository here. The two panels below are separated by a "splitter bar". You can drag the bar horizontally to view hidden code or output.
/*-------------------------------------------------------------------                              
  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]




                  

1.2 Point4D Class

This block presents code that defines a C++ type, Point4D. It defines the data held by instances of the type, three double precision coordinates and a std::time_t variable, and methods to create, copy, assign, modify and destroy instances. User-defined C++ types are described by classes. A class is a pattern for laying out an instance's data in the stack or heap, and methods that access and modify the data. Instances, i.e. objects, are created by invoking a constructor method, and are accessed and modified by other methods. Code that implements class methods resides in static memory, and has lifetime essentially equal to program lifetime.
/*---------------------------------------------------------         
  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;
}
Concept:

Point4D holds data for a point in 3 dimensional space and
a time when something was at that point.

These points could be collected into a vector to represent
a trajectory of an aircraft or a machine tool cutting edge.















 C++ class syntax:

C++ defines six special methods for construction, assignment,
and destruction, all based on class name. They are illustrated
in this block.

The C++ compiler will implement default copy constructor,
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.

The compiler does this by using its member's and base's
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.

However, the implemented methods are correct if, and only if,
class members and bases have correct copy, destruction, and
assignment semantics.

That is true for primitive types and collections from the
Standard Template Library (STL), but otherwise designers must
implement those methods.

This is a common source of errors so it is appropriate to
use the "default" or "delete" qualifiers to indicate that
the compiler generated methods will be correct.

That's done to make clear to a maintainer that the default
operation is intended, or to instruct the compiler not to
generate those methods by using the delete qualifier.

Function overloading:

C++ defines overloading of functions based on function
signature. 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".

Copy and move construction functions Point4D(...) are
overloads of the void constructor, Point4D(), and the copy
and move assignment operators are overloads.






 C++ operators are functions that are called when statements
with operator symbols are encountered, e.g., x = y is
equivalent to x.operator=(y) and std::cout << x is
equivalent to operator<<(std::cout, x).

The std::ostream operator<<(std::ostream& out, T& t) converts
objects of type T into parts that the default std::operator<<
can process. The overload for Point4D is needed by functions
in the AnalysisObjects.h library.

All the C++ class special methods are described in detail in STR, code for a user-defined string class. Methods may be defined inline, like xCoor and tCoor. Class data, like x and t, are declared private so they can only be mutated by methods of the class. Methods like xCoor that return references allow a class designer to selectively expose class data to user modification. Class methods may also be defined outside the bounds of the class declaration, as shown for Point4D(), timeToString(), et al. Moving all complex method definitions below the class declaration makes the class interface easier to understand.

1.3 Point4D Demo

The block below illustrates construction and operations of instances of the user-defined Point4D class. The void constructor, one with no arguments, is defined immediately below the Point4D class declaration. All other operations, e.g., copy construction, assignment, and destruction are implemented by the compiler, using element-wise operations. That is, for copy construction, the compiler generated code uses the copy construction code for each element. Source code is available here. Download the entire Bits repository here.
/*------------------------------------------------*/                                        
  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
  }

1.4 Heap-based operations

C++ code does not use a garbage collector to support creating and releasing memory allocations. Therefore class designers must manage those operations.

1.4.1 Managing std::String instances in the native heap

This block illustrates how that is done for instances of the std::String class, using the std::unique_ptr<T>. std::unique_ptr<T> instances are smart pointers that mimic standard C++ pointer operations, e.g., same interface for pointer operations, but automatically call delete on their internal pointer to heap instance when they go out of scope. That returns the allocation for future use by another program operation. Source code is available here. Download the entire Bits repository here.

  /*------------------------------------------------*/                                        
  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














1.4.2 Heap-based operations for std::Vector<T>

The code below substitutes std::Vector<T> for std::String in the code above. The operation syntax is the same. We show here that the address of the heap object is returned by sending the pointer to standard output, just like native pointers. Source code is available here. Download the entire Bits repository here.
/*------------------------------------------------*/                                         
    /* 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


1.4.3 Heap-based operations for user-defined Point4D

Using the same plan for execution as in the two blocks above, we see that all the methods of the heap-based Point4D instance are accessible using pointer operations, e.g., std::unique_ptr<T> uses the same pointer syntax for operations as the native C++ pointer. Source code is available here. Download the entire Bits repository here.
/*------------------------------------------------*/                                        
    /* 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!


1.5 AnalysisObj.h - Analysis and Display Functions

This block presents code for analysis and display of C++ objects. The source code is available here. Download the entire Bits repository here.
/*---------------------------------------------------------
  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();
}
Analysis and Display Functions

This code block contains definitions of ten functions, four 
of which are templates.  If this seems too complex for you 
right now, you don't have to understand them completely to 
understand this Bits demo.

You are invited to skim over the definitions to try to under-
stand what they do, not so much how they do it. You can come
back later to pick up any missing details.

The next Bit will explore generics and will help you under-
stand how these functions work.

Template functions:

Template functions are code generators that create function 
overloads for specific template argument types using a 
template pattern.

That creates function overloads for each T argument, e.g., 
three distinct functions generated from a single template 
function definition.

showType(T t, ...) is the only analysis function in this file. 
The next Bit will add several more.

The other functions simply format and display their instance 
arguments, or provide helper activities for display.

1.6 Program Structure

The block below illustrates how this program is structured using three files: PointsObj.h, AnalysisObj.h, and Cpp_Objects.cpp, and several functions defined in Cpp_Objects.cpp. The first two files are header-only libraries and the third defines execution flow for demonstration of C++ library and user-defined types. Source code is available here. Download the entire Bits repository here.
/*-------------------------------------------------------------------
  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");
}
Structure:




 Code in the left panel begins with a series of #include 
statements that import declarations for the standard 
library and also for two header only libraries defined 
in other files in this Bit.

The #include declaratons, shown on in the left panel, are 
being superceded by module imports, as of C++20.

For example, all of the standard library includes like 
#include <iostream> are being replaced with a single 
import std;. Individual libraries can be imported with 
declarations like:

import <iostream>;

These modern declarations are not used in this demon-
stration because the build tool I use, CMake, does not
support importing the std::libraries.

Modules do work with code compiled in the Visual Studio
IDE.

























 Execution Flow:

Processing begins on entry to the main function which,
in turn invokes several functions, devoted to demon-
strating standard library types and a custom type.
They show, seperately, placement of objects in stack 
memory then placement in the native heap.


2.0 Build

Build  
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
>

3.0 Visual Studio Code View

The code for this demo is available in github.com/JimFawcett/Bits. If you click on the Code dropdown you can clone the repository of all code for these demos to your local drive. Then, it is easy to bring up any example, in any of the languages, in VS Code. Here, we do that for Cpp\Cpp_Objects. Figure 1. VS Code IDE Figure 2. Launch.JSON Figure 3. Debugging Objects

4.0 References

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.
>