C++ class organization

General overview

This is from the sample solution for a 2015 assignment in which students were asked to write and analyze C++ code to answer the following questions (i.e. code/output/analysis that could answer the question without the need to resort to any other C/C++ reference material):

Each program's code and resulting output are appended further below.


Analysis of constructors/destructors

For statically declared variables, the constructors appear to be run when the variable's scope is entered, and the destructors are run when the scope leaves.

The constructors appear to run in the order of declaration for variables of the same scope, and the destructors run in the reverse order.

For global variables, this means the constructors all run when the program begins, before the main routine commences, and the destructors run after the main routine completes.

For cases where an object is passed-by-value to a function, the copy constructor for that class type executes to create the duplicate that is given to the function, thus the copy constructors run between the point of call and the point of entry to the function.

Interestingly, the destructors for the pass-by-value parameter do NOT appear to execute upon exiting the function.

With respect to inheritance and multiple inheritance, when an object is created the constructors for each of its ancestor classes runs prior to the constructor for the object itself, and the destructors for each of the ancestor classes run after the constructor for the object itself.

For dynamically allocated classes, the constructors are run on the call to new, and the destructors are run on the call to delete. If no call to delete is made then the destructors are not run (not even at the end of the program).


Analysis of method calls

For statically bound methods (the default), the specific method called is based entirely on the type of the object or pointer through which the call is made.

In cases where the method was inherited from another class, the "nearest" method is used. For example, if C inherits from B, which in turn inherits from A, then when C calls an inherited method the default will be to the version inherited from B.

For dynamically bound methods, the method called will be the one associated with the type of object currently being referenced, which need not be the same as the type of the pointer through which it is being referenced.


Analysis of memory organization

The overall organization of memory appears much as we found with assignment 5:

In terms of class-specific storage, results are largely as expected:

Size and alignment

Again, sizes and alignment of fields operates much as with structs in assignment 5. Class fields are stored in the order declared, with bytes of padding inserted to align the fields on appropriate boundaries (any for char/bool, even for short, quad for int/float, oct for long/double/pointers).

For classes that purely use static method binding, no extra storage space is allocated to hold method pointers, implying that the compiler inserts the correct function reference at the point of call for all static calls to methods.

Dynamic binding and impact on storage

However, for classes that can potentially call dynamically bound methods, the compiler inserts an extra pointer as the first field in the storage for the class - that pointer contains the address of a table in the code section (0x400000 area), which in turn contains the correct addresses to dynamically bind to methods for that class.

If the class is derived from other classes which also can potentially call dynamically bound methods then the storage structure for the class looks something like:

pointer to the class's table 
... regular fields for the class ...
pointer to the parent's table
... regular fields for the parent class ...
pointer to the grandparent's table
... regular fields for the grandparent class ...
etc.
Thus each object has inside it the references to all the tables defining where the dynamically bound methods can be found.


Code and output

Programs assign6a.cpp through assign6e.cpp are each shown below, along with their output.

assign6a.cpp
#include <cstdio>

// investigate C++ class sizes/content

class independant {
   public:
      char c0;
};

class independant0 {
   public:
      int i0;
};

class independantA {
   public:
      char c0;
      void f();
};

class independantB {
   public:
      int i0;
      void f();
      void g();
};

class independantC {
   public:
      char c1;  // new
      short s1; // new
      long l1;  // new
      char c2;  // new
      int i1;   // new
};

class parent {
   public:
      char c1;  // new
      short s1; // new
      long l1;  // new
      char c2;  // new
      int i1;   // new
};

class child: public parent {
   public:
      char c1;  // overrides inherited
      long l2;  // new
      char c3;  // new
};

class cousin {
   public:
      char c1; // new, matches parent
      long l2; // new, matches child
      char c4; // new
};

class descendant: public child, public cousin {
   public:
      char c1;  // overrides all three
      char c2;  // overrides parent
      char c3;  // overrides child
      char c4;  // overrides cousin
      char c5;  // new
};

class abstrbase {
   public:
      virtual void f() = 0;
};

class derived1: public abstrbase {
   public:
      void f();
};

class derived2: public abstrbase {
   public:
      void f();
      void g();
};

class derived3: public abstrbase {
   public:
      int i;
      void f();
      void g();
};

class abstrbase2 {
   public:
      virtual void f() = 0;
      virtual void g() = 0;
};

class derived4: public abstrbase2 {
   public:
      void f();
      void g();
};

class derived5: public abstrbase2 {
   public:
      void f();
      void g();
      void h();
};

class derived6: public abstrbase2 {
   public:
      int i;
      void f();
      void g();
      void h();
};

class alignment {
   public:
      char c1;
      short s1;
      long l1; 
      bool b1; 
      int i1;  
      long* p1; 
      char c2; 
      float f1;
      double d1; 
};

int main()
{
   printf("Data sizes\n");
   printf("   char %ld, bool %ld, ptr %ld\n", sizeof(char), sizeof(bool), sizeof(long*));
   printf("   short %ld, int %ld, long %ld\n", sizeof(short), sizeof(int), sizeof(long));
   printf("   float %ld, double %ld\n", sizeof(float), sizeof(double));
   printf("\nclass sizes\n");
   printf("   independant %ld (char)\n", sizeof(independant));
   printf("   independant0 %ld (int)\n", sizeof(independant0));
   printf("   independantA %ld (char, method)\n", sizeof(independantA));
   printf("   independantB %ld (int, 2 methods)\n", sizeof(independantB));
   printf("   independantC %ld (char, short, long, char, int)\n", sizeof(independantC));
   printf("   parent %ld (char, short, long, char, int)\n", sizeof(parent));
   printf("   child %ld (char, long, char + parent)\n", sizeof(child));
   printf("   cousin %ld (char, long, char)\n", sizeof(cousin));
   printf("   descendant %ld (5 chars, + child + cousin + parent)\n", sizeof(descendant));
   alignment a;
   printf("\nInternal alignment test, size %ld\n", sizeof(alignment));
   printf("   char %p\n", &(a.c1));
   printf("   short %p\n", &(a.s1));
   printf("   long %p\n", &(a.l1));
   printf("   bool %p\n", &(a.b1));
   printf("   int %p\n", &(a.i1));
   printf("   long* %p\n", &(a.p1));
   printf("   char %p\n", &(a.c2));
   printf("   float %p\n", &(a.f1));
   printf("   double %p\n", &(a.d1));
   printf("\nclass variable addresses\n");
   independant  ia, ib;
   independant0 i0a, i0b;
   independantA iaa, iab;
   parent pa, pb;
   printf("   independants a %p, b %p\n", &ia, &ib);
   printf("   independant0s a %p, b %p\n", &i0a, &i0b);
   printf("   independantAs a %p, b %p\n", &iaa, &iab);
   printf("   parents a %p, b %p\n", &pa, &pb);
   independant i; 
   parent p;
   independant0 i0;
   independantB b;
   printf("interleaved indep %p, parent %p, indep0 %p, indepB %p\n", &i, &p, &i0, &b);
   printf("\nDerived from abstract base with f a pure virtual\n");
   printf("   derived1 (just override f) %ld\n", sizeof(derived1));
   printf("   derived2 (overrides f, adds g) %ld\n", sizeof(derived2));
   printf("   derived3 (overrides f, adds g and int) %ld\n", sizeof(derived3));
   printf("\nDerived from abstract base with f,g pure virtuals\n");
   printf("   derived4 (overrides f, g) %ld\n", sizeof(derived4));
   printf("   derived5 (overrides f, g, adds h) %ld\n", sizeof(derived5));
   printf("   derived6 (overrides f, g adds h, int) %ld\n", sizeof(derived6));
}

void independantA::f()
{
   printf("A::f\n");
}

void independantB::f()
{
   printf("B::f\n");
}

void independantB::g()
{
   printf("B::g\n");
}

void derived1::f()
{
   printf("d1::f\n");
}

void derived2::f()
{
   printf("d2::f\n");
}

void derived2::g()
{
   printf("d2::g\n");
}

void derived3::f()
{
   printf("d3::f\n");
}

void derived3::g()
{
   printf("d3::g\n");
}

void derived4::f()
{
   printf("d4::f\n");
}

void derived4::g()
{
   printf("d4::g\n");
}

void derived5::f()
{
   printf("d5::f\n");
}

void derived5::g()
{
   printf("d5::g\n");
}

void derived5::h()
{
   printf("d5::h\n");
}

void derived6::f()
{
   printf("d6::f\n");
}

void derived6::g()
{
   printf("d6::g\n");
}

void derived6::h()
{
   printf("d6::h\n");
}

assign6a.txt
Data sizes
   char 1, bool 1, ptr 8
   short 2, int 4, long 8
   float 4, double 8

class sizes
   independant 1 (char)
   independant0 4 (int)
   independantA 1 (char, method)
   independantB 4 (int, 2 methods)
   independantC 24 (char, short, long, char, int)
   parent 24 (char, short, long, char, int)
   child 48 (char, long, char + parent)
   cousin 24 (char, long, char)
   descendant 80 (5 chars, + child + cousin + parent)

Internal alignment test, size 48
   char 0x7fff4a2270a0
   short 0x7fff4a2270a2
   long 0x7fff4a2270a8
   bool 0x7fff4a2270b0
   int 0x7fff4a2270b4
   long* 0x7fff4a2270b8
   char 0x7fff4a2270c0
   float 0x7fff4a2270c4
   double 0x7fff4a2270c8

class variable addresses
   independants a 0x7fff4a22716f, b 0x7fff4a22716e
   independant0s a 0x7fff4a227160, b 0x7fff4a227150
   independantAs a 0x7fff4a22714f, b 0x7fff4a22714e
   parents a 0x7fff4a227130, b 0x7fff4a227110
interleaved indep 0x7fff4a22710f, parent 0x7fff4a2270f0, indep0 0x7fff4a2270e0, indepB 0x7fff4a2270d0

Derived from abstract base with f a pure virtual
   derived1 (just override f) 8
   derived2 (overrides f, adds g) 8
   derived3 (overrides f, adds g and int) 16

Derived from abstract base with f,g pure virtuals
   derived4 (overrides f, g) 8
   derived5 (overrides f, g, adds h) 8
   derived6 (overrides f, g adds h, int) 16
assign6b.cpp
// assign6b.cpp:
//    investigating the handling of 
//       constructors, destructors, and method call binding
//    for each, need to consider
//       calls through an abstract base pointer
//       calls through the class defining the method
//       calls through a class inheriting the method
//           after overriding it
//       calls in cases of conflicts with multiple inheritance

#include <cstdio>

class AbstDynBase {
   public:
      AbstDynBase();
      ~AbstDynBase();
      virtual void print() = 0;
      void set(int d = 0);
      int get();
   protected:
      int data;
};

class ADBchild:public AbstDynBase {
   public:
      ADBchild();
      ~ADBchild();
      virtual void print();
      void set(int d = -1);
};

class Ancestor {
   public: 
      Ancestor(float init = 0);
      ~Ancestor();
      void print();
   protected:
      float Adata;
};

class ADBgrandch:public ADBchild, public Ancestor {
   public:
      ADBgrandch();
      ~ADBgrandch();
      virtual void print();
      int get();
};

class GrandChildB:public ADBchild, public Ancestor {
   public:
       // only exists to see what happens with call to conflicting
       //    prints inherited from ADBchild and Ancestor
};

// create global object variable and constant with unique initial values
//   to see when they run their constructors and destructors
Ancestor globalA1(0.1);
const Ancestor constA1(0.2);

int main()
{
   printf("\nMain routine, declaring child\n");
   ADBchild c;
   printf("Main routine, setting 3 in child (child set?)\n");
   c.set(3);
   printf("Main routine, printing in child (child print?)\n");
   c.print();
   printf("Main routine, calling get in child (inherited get?): %d\n", c.get());

   printf("\nMain routine, declaring grandchild\n");
   ADBgrandch g;
   printf("Main routine, setting 5 in grandchild (inherited set?)\n");
   g.set(5);
   printf("Main routine, printing in grandchild (grandchild print?)\n");
   g.print();
   printf("Main routine, getting grandchild (grandchild get?): %d\n", g.get());

   printf("\nMain routine, declaring AbstDynBase ptr to a child\n");
   AbstDynBase *ac = new ADBchild;
   printf("Main routine, setting -1 in abstrbase child (child set?)\n");
   ac->set(-1);
   printf("Main routine, printing in abstrbase child (child print?)\n");
   ac->print();
   printf("Main routine, getting abstrbase child (inherited get?): %d\n", ac->get());
   printf("Main routine, deleting abstrbase child (which destructor?)\n");
   delete ac;
   
   printf("\nMain routine, declaring AbstDynBase ptr to a grandchild\n");
   ac = new ADBgrandch;
   printf("Main routine, setting 10 in abstrbase grandchild (inherited set?)\n");
   ac->set(10);
   printf("Main routine, printing in abstrbase grandchild (grandchild print?)\n");
   ac->print();
   printf("Main routine, getting abstrbase grandchild (grandchild get?): %d\n", ac->get());
   printf("Main routine, deleting abstrbase grandchild (which destructor?)\n");
   delete ac;
   
   printf("\nTrying call to print in case of multiple inheritance,\n");
   printf("  inheriting print from both lines, not overriding\n");
   GrandChildB gcB; 
   printf("Compile time error due to ambiguity: GrandChildB gcB; gcB.print();\n");
   printf("Calling once on ancestor, once on child using explicit references\n");
   gcB.Ancestor::print();
   gcB.ADBchild::print();

   printf("\nMain routine, declaring AbstDynBase ptr to a grandchild\n");
   ac = new ADBgrandch;
   printf("Main routine, setting 100 in abstrbase grandchild\n");
   ac->set(100);
   printf("(and explicitly not deleting it to see what happens at program end)\n");

   printf("\nEnd of main routine\n");
}

AbstDynBase::AbstDynBase()
{
   printf("Abstract base constructor, data set to 0\n");
   data = 0;
}

AbstDynBase::~AbstDynBase()
{
   printf("Abstract base destructor, data is %d\n", data);
}

void AbstDynBase::set(int d)
{
   printf("abstrbase set, data goes from %d to %d\n", data, d);
   data = d;
}

int AbstDynBase::get()
{
   printf("abstrbase get, data is %d\n", data);
   return data;
}

ADBchild::ADBchild()
{
   int d = data - 1;
   printf("child constructor, data was %d, now %d\n", data, d);
   data = d;
}

ADBchild::~ADBchild()
{
   printf("child destructor, data is %d\n", data);
}

void ADBchild::print()
{
   printf("child print, data is %d\n", data);
}

void ADBchild::set(int d)
{
   printf("child set, data goes from %d to %d\n", data, d);
   data = d;
}

ADBgrandch::ADBgrandch()
{
   int d = -data;
   printf("grandchild constructor, data was %d, now %d\n", data, d);
   data = d;
}

ADBgrandch::~ADBgrandch()
{
   printf("grandchild destructor, data is %d\n", data);
}

void ADBgrandch::print()
{
   printf("grandchild print, data is %d\n", data);
}

int ADBgrandch::get()
{
   printf("grandchild get, data is %d\n", data);
   return data;
}

Ancestor::Ancestor(float init)
{
   Adata = init;
   printf("Ancestor constructor, Adata is %f\n", Adata);
}

Ancestor::~Ancestor()
{
   printf("Ancestor destructor, Adata is %g\n", Adata);
}

void Ancestor::print()
{
   printf("Ancestor print, Adata is %g\n", Adata);
}
assign6b.txt
Ancestor constructor, Adata is 0.100000
Ancestor constructor, Adata is 0.200000

Main routine, declaring child
Abstract base constructor, data set to 0
child constructor, data was 0, now -1
Main routine, setting 3 in child (child set?)
child set, data goes from -1 to 3
Main routine, printing in child (child print?)
child print, data is 3
abstrbase get, data is 3
Main routine, calling get in child (inherited get?): 3

Main routine, declaring grandchild
Abstract base constructor, data set to 0
child constructor, data was 0, now -1
Ancestor constructor, Adata is 0.000000
grandchild constructor, data was -1, now 1
Main routine, setting 5 in grandchild (inherited set?)
child set, data goes from 1 to 5
Main routine, printing in grandchild (grandchild print?)
grandchild print, data is 5
grandchild get, data is 5
Main routine, getting grandchild (grandchild get?): 5

Main routine, declaring AbstDynBase ptr to a child
Abstract base constructor, data set to 0
child constructor, data was 0, now -1
Main routine, setting -1 in abstrbase child (child set?)
abstrbase set, data goes from -1 to -1
Main routine, printing in abstrbase child (child print?)
child print, data is -1
abstrbase get, data is -1
Main routine, getting abstrbase child (inherited get?): -1
Main routine, deleting abstrbase child (which destructor?)
Abstract base destructor, data is -1

Main routine, declaring AbstDynBase ptr to a grandchild
Abstract base constructor, data set to 0
child constructor, data was 0, now -1
Ancestor constructor, Adata is 0.000000
grandchild constructor, data was -1, now 1
Main routine, setting 10 in abstrbase grandchild (inherited set?)
abstrbase set, data goes from 1 to 10
Main routine, printing in abstrbase grandchild (grandchild print?)
grandchild print, data is 10
abstrbase get, data is 10
Main routine, getting abstrbase grandchild (grandchild get?): 10
Main routine, deleting abstrbase grandchild (which destructor?)
Abstract base destructor, data is 10

Trying call to print in case of multiple inheritance,
  inheriting print from both lines, not overriding
Abstract base constructor, data set to 0
child constructor, data was 0, now -1
Ancestor constructor, Adata is 0.000000
Compile time error due to ambiguity: GrandChildB gcB; gcB.print();
Calling once on ancestor, once on child using explicit references
Ancestor print, Adata is 0
child print, data is -1

Main routine, declaring AbstDynBase ptr to a grandchild
Abstract base constructor, data set to 0
child constructor, data was 0, now -1
Ancestor constructor, Adata is 0.000000
grandchild constructor, data was -1, now 1
Main routine, setting 100 in abstrbase grandchild
abstrbase set, data goes from 1 to 100
(and explicitly not deleting it to see what happens at program end)

End of main routine
Ancestor destructor, Adata is 0
child destructor, data is -1
Abstract base destructor, data is -1
grandchild destructor, data is 5
Ancestor destructor, Adata is 0
child destructor, data is 5
Abstract base destructor, data is 5
child destructor, data is 3
Abstract base destructor, data is 3
Ancestor destructor, Adata is 0.2
Ancestor destructor, Adata is 0.1
assign6c.cpp
#include <cstdio>

#define CONTENTS(X) ((* (long*)(&X)))


// investigating vtable implementation of
//    dynamically-bound methods

class abstrBaseA {
   public:
      virtual long* f() = 0;
};

class abstrBaseB {
   public:
      virtual long* g() = 0;
      virtual long* h() = 0;
};

class abstrBaseC {
   public:
      virtual long* f() = 0; // profile matches A::f
      virtual long* g(int i) = 0; // profile mismatch with B::g
};

class derivedA1: public abstrBaseA {
   public:
      long* f();
};

class derivedB1: public abstrBaseB {
   public:
      long* g();
      long* h();
};

class derivedAB: public abstrBaseA, public abstrBaseB {
   public:
      long* f();
      long* g();
      long* h();
};

class derivedABC: public abstrBaseA, public abstrBaseB, public abstrBaseC {
   public:
      long* f(); // matches A::f and C::f
      long* g();  // matches B::g
      long* g(int i); // matches C::g
      long* h(); // matches B::h
};

class nextGen: public derivedABC {
   public:
      long* h(); // overrides ABC::h
      // relies on inherited methods from ABC for A::f, C::f, B::g, C::g
};

long* derivedA1::f()
{
A1_F:
    printf("derivedA1::f() %p", &&A1_F);
    return (long*)(&&A1_F);
}

long* derivedB1::g()
{
B1_G:
    printf("derivedB1::g() %p", &&B1_G);
    return (long*)(&&B1_G);
}

long* derivedB1::h()
{
B1_H:
    printf("derivedB1::h() %p", &&B1_H);
    return (long*)(&&B1_H);
}

long* derivedAB::f()
{
AB_F:
    printf("derivedAB::f() %p", &&AB_F);
    return (long*)(&&AB_F);
}

long* derivedAB::g()
{
AB_G:
    printf("derivedAB::g() %p", &&AB_G);
    return (long*)(&&AB_G);
}

long* derivedAB::h()
{
AB_H:
    printf("derivedAB::h() %p", &&AB_H);
    return (long*)(&&AB_H);
}

long* derivedABC::f()
{
ABC_F:
    printf("derivedABC::f() %p", &&ABC_F);
    return (long*)(&&ABC_F);
}

long* derivedABC::g()
{
ABCG_VOID:
    printf("derivedABC::g() %p", &&ABCG_VOID);
    return (long*)(&&ABCG_VOID);
}

long* derivedABC::g(int i)
{
ABCG_INT:
    printf("derivedABC::g(i) %p", &&ABCG_INT);
    return (long*)(&&ABCG_INT);
}

long* derivedABC::h()
{
ABC_H:
    printf("derivedABC::h %p", &&ABC_H);
    return (long*)(&&ABC_H);
}

long* nextGen::h()
{
NG_H:
    printf("nextGen::h %p", &&NG_H);
    return (long*)(&&NG_H);
}

void printSeries(long* ptr)
{
   printf("      ptr[0]: %x, ptr[1]: %x, ptr[2]: %x, ptr[3]: %x\n", ptr[0], ptr[1], ptr[2], ptr[3]);
   printf("      ptr[4]: %x, ptr[5]: %x, ptr[6]: %x, ptr[7]: %x\n", ptr[4], ptr[5], ptr[6], ptr[3]);
   printf("      ptr[8]: %x, ptr[9]: %x, ptr[10]: %x, ptr[11]: %x\n", ptr[8], ptr[9], ptr[10], ptr[11]);
   printf("      ptr[12]: %x, ptr[13]: %x, ptr[14]: %x, ptr[15]: %x\n", ptr[12], ptr[13], ptr[14], ptr[15]);
   printf("      ptr[16]: %x, ptr[17]: %x, ptr[18]: %x, ptr[19]: %x\n", ptr[16], ptr[17], ptr[18], ptr[19]);
}

int main()
{
   derivedA1  a1;
   derivedB1  b1;
   derivedAB  ab;
   derivedABC abc;
   nextGen    ng;
   printf("\nMethod start label addresses, table offsets, returned addresses\n");
   printf("   A1::f %p, %p\n",     &derivedA1::f,  a1.f());
   printf("   B1::g %p, %p\n",     &derivedB1::g,  b1.g());
   printf("   B1::h %p, %p\n",     &derivedB1::h,  b1.h());
   printf("   AB::f %p, %p\n",     &derivedAB::f,  ab.f());
   printf("   AB::g %p, %p\n",     &derivedAB::g,  ab.g());
   printf("   AB::h %p, %p\n",     &derivedAB::h,  ab.h());
   printf("   ABC::f %p, %p\n",    &derivedABC::f, abc.f());
   printf("   ABC::g --, %p\n",                    abc.derivedABC::g());
   printf("   ABC::g(i) --, %p\n",                 abc.derivedABC::g(0));
   printf("   ABC::h %p, %p\n",    &derivedABC::h, abc.h());
   printf("   NG::h %p, %p\n",     &nextGen::h, ng.h());
   printf("\nAddresses of objects, first content there (vtable), vtable content\n");
   long* table = (long*)CONTENTS(a1);
   printf("   a1 %p, %p, %p\n", &a1, table, (long*)(*table)); 
   printSeries(table);
   table = (long*)CONTENTS(b1);
   printf("   b1 %p, %p, %p\n", &b1, table, (long*)(*table));
   printSeries(table);
   table = (long*)CONTENTS(ab);
   printf("   ab %p, %p, %p\n", &ab, table, (long*)(*table));
   printSeries(table);
   table = (long*)CONTENTS(abc);
   printf("   abc %p, %p, %p\n", &abc,table, (long*)(*table));
   printSeries(table);
   table = (long*)CONTENTS(ng);
   printf("   ng %p, %p, %p\n", &ng, table, (long*)(*table));
   printSeries(table);
}

assign6c.txt

Method start label addresses, table offsets, returned addresses
derivedA1::f() 0x4008b8   A1::f 0x1, (nil)
derivedB1::g() 0x4008e0   B1::g 0x1, (nil)
derivedB1::h() 0x400908   B1::h 0x9, (nil)
derivedAB::f() 0x400930   AB::f 0x1, (nil)
derivedAB::g() 0x400958   AB::g 0x9, (nil)
derivedAB::h() 0x400986   AB::h 0x11, (nil)
derivedABC::f() 0x4009b4   ABC::f 0x1, (nil)
derivedABC::g() 0x4009e2   ABC::g --, 0x4009e2
derivedABC::g(i) 0x400a13   ABC::g(i) --, 0x400a13
derivedABC::h 0x400a40   ABC::h 0x19, (nil)
nextGen::h 0x400a6e   NG::h 0x19, (nil)

Addresses of objects, first content there (vtable), vtable content
   a1 0x7fffde6dacd0, 0x401790, 0x4008ac
      ptr[0]: 4008ac, ptr[1]: 0, ptr[2]: 0, ptr[3]: 401950
      ptr[4]: 400770, ptr[5]: 400770, ptr[6]: 0, ptr[7]: 401950
      ptr[8]: 400770, ptr[9]: 400770, ptr[10]: 0, ptr[11]: 401990
      ptr[12]: 400770, ptr[13]: 0, ptr[14]: 602310, ptr[15]: 401818
      ptr[16]: 401840, ptr[17]: 78656e37, ptr[18]: 0, ptr[19]: 0
   b1 0x7fffde6dacc0, 0x401770, 0x4008d4
      ptr[0]: 4008d4, ptr[1]: 4008fc, ptr[2]: 0, ptr[3]: 401920
      ptr[4]: 4008ac, ptr[5]: 0, ptr[6]: 0, ptr[7]: 401920
      ptr[8]: 400770, ptr[9]: 400770, ptr[10]: 0, ptr[11]: 401970
      ptr[12]: 400770, ptr[13]: 400770, ptr[14]: 0, ptr[15]: 401990
      ptr[16]: 400770, ptr[17]: 0, ptr[18]: 602310, ptr[19]: 401818
   ab 0x7fffde6dacb0, 0x401710, 0x400924
      ptr[0]: 400924, ptr[1]: 40094c, ptr[2]: 40097a, ptr[3]: fffffff8
      ptr[4]: 4018a0, ptr[5]: 400973, ptr[6]: 4009a1, ptr[7]: fffffff8
      ptr[8]: 0, ptr[9]: 0, ptr[10]: 0, ptr[11]: 4018f0
      ptr[12]: 4008d4, ptr[13]: 4008fc, ptr[14]: 0, ptr[15]: 401920
      ptr[16]: 4008ac, ptr[17]: 0, ptr[18]: 0, ptr[19]: 401950
   abc 0x7fffde6dac90, 0x401690, 0x4009a8
      ptr[0]: 4009a8, ptr[1]: 4009d6, ptr[2]: 400a04, ptr[3]: 400a34
      ptr[4]: fffffff8, ptr[5]: 401840, ptr[6]: 4009fd, ptr[7]: 400a34
      ptr[8]: fffffff0, ptr[9]: 401840, ptr[10]: 4009cf, ptr[11]: 400a2e
      ptr[12]: 0, ptr[13]: 0, ptr[14]: 0, ptr[15]: 4018a0
      ptr[16]: 400924, ptr[17]: 40094c, ptr[18]: 40097a, ptr[19]: fffffff8
   ng 0x7fffde6dac70, 0x401610, 0x4009a8
      ptr[0]: 4009a8, ptr[1]: 4009d6, ptr[2]: 400a04, ptr[3]: 400a62
      ptr[4]: fffffff8, ptr[5]: 401800, ptr[6]: 4009fd, ptr[7]: 400a62
      ptr[8]: fffffff0, ptr[9]: 401800, ptr[10]: 4009cf, ptr[11]: 400a2e
      ptr[12]: 0, ptr[13]: 0, ptr[14]: 0, ptr[15]: 401840
      ptr[16]: 4009a8, ptr[17]: 4009d6, ptr[18]: 400a04, ptr[19]: 400a34
assign6d.cpp
// assign6d.cpp: 
//   investigating the memory arrangement of classes,
//      both with respect to overall memory structure
//      and with respect to stack frames

#include <cstdio>

// general constant to show relative location to other test values
const int TestConst = 3;

// general global variable to show relative location to other test values
int TestGlobal = 4;

class AbstDynBase {
   public:
      AbstDynBase();
      virtual void print() = 0;
      void set(int d = 0);
      int get();
      // create a class constant, each instance gets a copy
      const long AbstConst = -1;
      // create a static class constant, one shared across all instances
      static const long AbstStaticConst;
   protected:
      // create a class variable, each instance gets a copy
      int data;
      // create a static class variable, one shared across all instances
      static int shared;
};

class ADBchild:public AbstDynBase {
   public:
      ADBchild();
      virtual void print();
      void set(int d = -1);
      static void checkSetShared(int i);
   protected:
      static int shared;
      int data;
}; 

// initialize the shared class variables and constants
int AbstDynBase::shared = 1;
int ADBchild::shared = 2;
const long AbstDynBase::AbstStaticConst = -2;

class Ancestor {
   public: 
      Ancestor();
      void print();
   protected:
      int data;
};

class ADBgrandch:public ADBchild, public Ancestor {
   public:
      ADBgrandch(int d = -1);
      ADBgrandch(const ADBgrandch& g); // copy constructor
      ~ADBgrandch();
      virtual void print();
      int get();
   protected:
      int data;
      char c1, c2, c3;
      short s1;
      long L1;
      char c4;
      int i1;
      char c5;
      double d1;
 
};

void examineParams(ADBgrandch &g1, ADBgrandch g2);

// create a global grandchild
ADBgrandch globGC(100);

// create a const global ancestor
const Ancestor globA;

int main(int argc, char* argv[])
{
   double init = 1;

   printf("Address of main: %p\n\n", main);
   printf("Display the method addresses\n");
   printf("   AbstDynBase::get() %p\n", (void*)(&AbstDynBase::get));
   printf("                set() %p\n", (void*)(&AbstDynBase::set));
   printf("   ADBchild::print() %p\n", (void*)(&ADBchild::print));
   printf("             set() %p\n", (void*)(&ADBchild::set));
   printf("             checkSetShared() %p\n", (void*)(&ADBchild::checkSetShared));
   printf("   Ancestor::print() %p\n", (void*)(&Ancestor::print));
   printf("   ADBgrandch::print() %p\n", (void*)(&ADBgrandch::print));
   printf("               get() %p\n", (void*)(&ADBgrandch::get));


   // create a local instance of a grandchild and investigate the struct contents
   ADBgrandch g(0), h(1);
   printf("\nAddress of local g %p\n", &g);
   g.print();
   printf("\nAddress of local h %p\n", &h);
   h.print();
   printf("\nCalling grandchild get\n");
   int i = h.get();

   // create a static local instance of a grandchild and investigate the struct contents
   static ADBgrandch s;
   printf("Printing static local grandchild\n");
   s.print();

   // create a const local instance of an ancestor
   const Ancestor A1;
    
   // create a static local const of an ancestor
   static const Ancestor SA1;

   // display the locations of the global variable, global constant,
   //    local variable, local constant, static local var, static local const  
   printf("\nExamples of instance locations:\n");
   printf("   global variable: %p\n", &globGC);
   printf("   global constant: %p\n", &globA);
   printf("   local variable: %p\n", &g);
   printf("   local constant: %p\n", &A1);
   printf("   static local variable: %p\n", &s);
   printf("   static local constant: %p\n", &SA1);

   // dynamically allocate a grandchild
   printf("\nCreating and printing a dynamic grandchild\n");
   ADBgrandch *dynGC = new ADBgrandch(5);
   dynGC->print();
   printf("\nCreating and printing a dynamic grandchild through and abstract base pointer\n");
   AbstDynBase *absGC = new ADBgrandch(20);
   absGC->print();

   // display the locations of the global variable, global constant,
   //    local variable, local constant, static local var, static local const  
   printf("\nExamples of instance locations:\n");
   printf("   global variable: %p\n", &globGC);
   printf("   global constant: %p\n", &globA);
   printf("   local variable: %p\n", &g);
   printf("   local constant: %p\n", &A1);
   printf("   static local variable: %p\n", &s);
   printf("   static local constant: %p\n", &SA1);
   printf("   heap dynamic: %p\n", dynGC);

   // check the locations of the various grandchild objects
   printf("\nGrandchild object locations:\n");
   printf("   static local s: %p\n", &s);
   printf("   global globGC: %p\n", &globGC);
   printf("   local g: %p\n", &g);
   printf("   local h: %p\n", &h);
   printf("   heap dynamic dynGC: %p\n", dynGC);
   printf("   abstr heap dynamic absGC: %p\n", absGC);
   printf("\nNote that main\'s argc param is at %p, local init is at %p\n", &argc, &init);
   printf("global TestConst %p, global TestGlobal %p\n", &TestConst, &TestGlobal);
   printf("\nLocations of abstract base constant as accessed through different objects\n");
   printf("   through static local s: %p\n", &s.AbstConst);
   printf("   through local g: %p\n", &g.AbstConst);
   printf("   through local h: %p\n", &h.AbstConst);
   printf("   through global globGC: %p\n", &globGC.AbstConst);
   printf("   through heap dynamic: %p\n", &dynGC->AbstConst);
   printf("   through heap dynamic + abst base ptr: %p\n", &absGC->AbstConst);
   printf("Location of static abstract base constant %p\n", &AbstDynBase::AbstStaticConst);

   // examine parameter passing of classess
   //    local g passed by ref, h by value
   printf("\nAbout to call examineParams, g passed by ref, h by value\n");
   examineParams(g, h);

   // check and set the shared data field/method through a couple of accesses
   ADBchild::checkSetShared(5);
   ADBchild::checkSetShared(3);
}

AbstDynBase::AbstDynBase()
{
   static int abstBaseCalls = 0;
   printf("AbstDynBase constructor call number %d\n", abstBaseCalls);
   if (abstBaseCalls == 0) {
      printf("AbstDynBase constructor static local is at %p\n", &abstBaseCalls);
   }
   abstBaseCalls++;
   data = 0;
}

void AbstDynBase::set(int d)
{
   data = d;
}

int AbstDynBase::get()
{
   return data;
}

ADBchild::ADBchild()
{
   int d = data - 1;
   data = d;
}

void ADBchild::print()
{
}

void ADBchild::set(int d)
{
   data = d;
}

void ADBchild::checkSetShared(int i)
{
   printf("\nChecking/setting ADBchild class static variables through static method\n");
   printf("   default %p, %d\n", &shared, shared);
   printf("   AbstDynBase::shared %p, value %d\n", &AbstDynBase::shared, AbstDynBase::shared);
   printf("   ADBchild::shared %p, value %d\n", &ADBchild::shared, ADBchild::shared);
   AbstDynBase::shared = i;
   ADBchild::shared = -i;
}

ADBgrandch::~ADBgrandch()
{
   printf("ADBgrandch destructor, data is %d\n", data);
}

ADBgrandch::ADBgrandch(int d)
{
   printf("Running ADBgrandch constructor\n");
   if (d == -1) {
      printf("   using default arg, this is probably the static local\n");
   } else if (d == 100) {
      printf("   using arg 100, this is probably the global\n");
   }
   data = d;
   c1 = '1';
   c2 = '2';
   c3 = '3'; 
   s1 = 0;
   L1 = 1;
   c4 = '4';
   i1 = 2;
   c5 = '5';
   d1 = 3;
}

void ADBgrandch::print()
{
   static int grandCalls = 0;
   printf("ADBgrandch print call number %d\n", grandCalls);
   if (grandCalls == 0) {
      printf("  grandCalls static local is at %p\n", &grandCalls);
      printf("  AbstConst is at %p\n", &AbstConst);
   }
   grandCalls++;
INPRINT:
   printf("Address of this print statement: %p\n\n", &&INPRINT);
   printf("\nDisplay the ADBgrandch field addresses\n");
   printf("   print own data addr %p\n", &data);
   printf("   print ancestor data addr %p\n", &(Ancestor::data));
   printf("   print child data addr %p\n", &(ADBchild::data));
   printf("   print base data addr %p\n", &(AbstDynBase::data));
   printf("   print this object addr %p\n", this);
   long *ptr1 = (long*)(this);
   long *ptr2 = (long*)(*ptr1);
   long *ptr3 = (long*)(*ptr2);
   printf("      contents of memory at \'this\' addr %x\n", (*ptr1));
   printf("                contents at ^that^ addr %x\n", (*ptr2));
   printf("                contents at ^that^ addr %x\n", (*ptr3));
   ptr1++; printf("      contents of memory at this++ addr (%p) %x\n",  ptr1, (*ptr1));
   ptr1++; printf("      contents of memory at this+2x addr (%p) %x\n",  ptr1, (*ptr1));
   ptr1++; printf("      contents of memory at this+3x addr (%p) %x\n",  ptr1, (*ptr1));
   ptr1++; printf("      contents of memory at this+4x addr (%p) %x\n",  ptr1, (*ptr1));
   ptr1++; printf("      contents of memory at this+5x addr (%p) %x\n",  ptr1, (*ptr1));
   ptr1++; printf("      contents of memory at this+6x addr (%p) %x\n",  ptr1, (*ptr1));
   ptr1++; printf("      contents of memory at this+7x addr (%p) %x\n",  ptr1, (*ptr1));
   ptr1++; printf("      contents of memory at this+8x addr (%p) %x\n",  ptr1, (*ptr1));
   printf("   print size of this object %ld\n", sizeof(ADBgrandch));
   printf("And investigating field locations/alignments\n");
   printf("  c1 %p, c2 %p, c3 %p\n", &c1, &c2, &c3);
   printf("  s1 %p, L1 %p, c4 %p\n", &s1, &L1, &c4);
   printf("  i1 %p, c5 %p, d1 %p\n", &i1, &c5, &d1);
}

int ADBgrandch::get()
{
INGET:
   long *ptr1 = (long*)(this);
   long *ptr2 = (long*)(*ptr1);
   long *ptr3 = (long*)(*ptr2);
   printf("In grandchild get method\n");
   printf("   address of start of method: %p\n", &&INGET);
   printf("   contents of memory at \'this\' addr %x\n", (*ptr1));
   printf("             contents at ^that^ addr %x\n", (*ptr2));
   printf("             contents at ^that^ addr %x\n", (*ptr3));
   return data;
}

Ancestor::Ancestor()
{
   data = 13;
}

void Ancestor::print()
{
}

void examineParams(ADBgrandch &g1, ADBgrandch g2)
{
   // note that g1 is a pointer to g
   // while g2 is an entirely new ADBgranch instance,
   //    whose values were provided by the copy constructor 
   //    during the call, i.e. a new grandchild copied from h
   long* ptr1 = (long*)(&g1);
   long* ptr2 = (long*)(&g2);
   printf("\nInside examineParams, param locations %p, %p\n", ptr1, ptr2);
   printf("   sizes %ld, %ld\n", sizeof(g1), sizeof(g2));
   printf("   values %p, %p\n", (*ptr1), (*ptr2));
   ptr1 = (long*)(&ptr2); printf("loc of local ptr2 %p, contents there %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up 8 bytes %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
   ptr1++; printf("   up another 8 %p, %p\n", ptr1, (*ptr1));
}

ADBgrandch::ADBgrandch(const ADBgrandch& g)
{
   // copy constructor
   printf("running grandchild copy constructor\n");
}

assign6d.txt
AbstDynBase constructor call number 0
AbstDynBase constructor static local is at 0x603464
Running ADBgrandch constructor
   using arg 100, this is probably the global
Address of main: 0x400afc

Display the method addresses
   AbstDynBase::get() 0x4011c0
                set() 0x4011a8
   ADBchild::print() 0x40120e
             set() 0x401218
             checkSetShared() 0x401230
   Ancestor::print() 0x40177a
   ADBgrandch::print() 0x4013ac
               get() 0x4016ca
AbstDynBase constructor call number 1
Running ADBgrandch constructor
AbstDynBase constructor call number 2
Running ADBgrandch constructor

Address of local g 0x7ffc0f183c60
ADBgrandch print call number 0
  grandCalls static local is at 0x603460
  AbstConst is at 0x7ffc0f183c68
Address of this print statement: 0x401416


Display the ADBgrandch field addresses
   print own data addr 0x7ffc0f183c7c
   print ancestor data addr 0x7ffc0f183c78
   print child data addr 0x7ffc0f183c74
   print base data addr 0x7ffc0f183c70
   print this object addr 0x7ffc0f183c60
      contents of memory at 'this' addr 402790
                contents at ^that^ addr 4013ac
                contents at ^that^ addr e5894855
      contents of memory at this++ addr (0x7ffc0f183c68) ffffffff
      contents of memory at this+2x addr (0x7ffc0f183c70) 0
      contents of memory at this+3x addr (0x7ffc0f183c78) d
      contents of memory at this+4x addr (0x7ffc0f183c80) 333231
      contents of memory at this+5x addr (0x7ffc0f183c88) 1
      contents of memory at this+6x addr (0x7ffc0f183c90) f183d34
      contents of memory at this+7x addr (0x7ffc0f183c98) e21b6635
      contents of memory at this+8x addr (0x7ffc0f183ca0) 0
   print size of this object 72
And investigating field locations/alignments
  c1 0x7ffc0f183c80, c2 0x7ffc0f183c81, c3 0x7ffc0f183c82
  s1 0x7ffc0f183c84, L1 0x7ffc0f183c88, c4 0x7ffc0f183c90
  i1 0x7ffc0f183c94, c5 0x7ffc0f183c98, d1 0x7ffc0f183ca0

Address of local h 0x7ffc0f183cb0
ADBgrandch print call number 1
Address of this print statement: 0x401416


Display the ADBgrandch field addresses
   print own data addr 0x7ffc0f183ccc
   print ancestor data addr 0x7ffc0f183cc8
   print child data addr 0x7ffc0f183cc4
   print base data addr 0x7ffc0f183cc0
   print this object addr 0x7ffc0f183cb0
      contents of memory at 'this' addr 402790
                contents at ^that^ addr 4013ac
                contents at ^that^ addr e5894855
      contents of memory at this++ addr (0x7ffc0f183cb8) ffffffff
      contents of memory at this+2x addr (0x7ffc0f183cc0) 0
      contents of memory at this+3x addr (0x7ffc0f183cc8) d
      contents of memory at this+4x addr (0x7ffc0f183cd0) 333231
      contents of memory at this+5x addr (0x7ffc0f183cd8) 1
      contents of memory at this+6x addr (0x7ffc0f183ce0) 603234
      contents of memory at this+7x addr (0x7ffc0f183ce8) 603435
      contents of memory at this+8x addr (0x7ffc0f183cf0) 0
   print size of this object 72
And investigating field locations/alignments
  c1 0x7ffc0f183cd0, c2 0x7ffc0f183cd1, c3 0x7ffc0f183cd2
  s1 0x7ffc0f183cd4, L1 0x7ffc0f183cd8, c4 0x7ffc0f183ce0
  i1 0x7ffc0f183ce4, c5 0x7ffc0f183ce8, d1 0x7ffc0f183cf0

Calling grandchild get
In grandchild get method
   address of start of method: 0x4016d6
   contents of memory at 'this' addr 402790
             contents at ^that^ addr 4013ac
             contents at ^that^ addr e5894855
AbstDynBase constructor call number 3
Running ADBgrandch constructor
   using default arg, this is probably the static local
Printing static local grandchild
ADBgrandch print call number 2
Address of this print statement: 0x401416


Display the ADBgrandch field addresses
   print own data addr 0x60349c
   print ancestor data addr 0x603498
   print child data addr 0x603494
   print base data addr 0x603490
   print this object addr 0x603480
      contents of memory at 'this' addr 402790
                contents at ^that^ addr 4013ac
                contents at ^that^ addr e5894855
      contents of memory at this++ addr (0x603488) ffffffff
      contents of memory at this+2x addr (0x603490) 0
      contents of memory at this+3x addr (0x603498) d
      contents of memory at this+4x addr (0x6034a0) 333231
      contents of memory at this+5x addr (0x6034a8) 1
      contents of memory at this+6x addr (0x6034b0) 34
      contents of memory at this+7x addr (0x6034b8) 35
      contents of memory at this+8x addr (0x6034c0) 0
   print size of this object 72
And investigating field locations/alignments
  c1 0x6034a0, c2 0x6034a1, c3 0x6034a2
  s1 0x6034a4, L1 0x6034a8, c4 0x6034b0
  i1 0x6034b4, c5 0x6034b8, d1 0x6034c0

Examples of instance locations:
   global variable: 0x603400
   global constant: 0x603448
   local variable: 0x7ffc0f183c60
   local constant: 0x7ffc0f183d00
   static local variable: 0x603480
   static local constant: 0x6034c8

Creating and printing a dynamic grandchild
AbstDynBase constructor call number 4
Running ADBgrandch constructor
ADBgrandch print call number 3
Address of this print statement: 0x401416


Display the ADBgrandch field addresses
   print own data addr 0x19b202c
   print ancestor data addr 0x19b2028
   print child data addr 0x19b2024
   print base data addr 0x19b2020
   print this object addr 0x19b2010
      contents of memory at 'this' addr 402790
                contents at ^that^ addr 4013ac
                contents at ^that^ addr e5894855
      contents of memory at this++ addr (0x19b2018) ffffffff
      contents of memory at this+2x addr (0x19b2020) 0
      contents of memory at this+3x addr (0x19b2028) d
      contents of memory at this+4x addr (0x19b2030) 333231
      contents of memory at this+5x addr (0x19b2038) 1
      contents of memory at this+6x addr (0x19b2040) 34
      contents of memory at this+7x addr (0x19b2048) 35
      contents of memory at this+8x addr (0x19b2050) 0
   print size of this object 72
And investigating field locations/alignments
  c1 0x19b2030, c2 0x19b2031, c3 0x19b2032
  s1 0x19b2034, L1 0x19b2038, c4 0x19b2040
  i1 0x19b2044, c5 0x19b2048, d1 0x19b2050

Creating and printing a dynamic grandchild through and abstract base pointer
AbstDynBase constructor call number 5
Running ADBgrandch constructor
ADBgrandch print call number 4
Address of this print statement: 0x401416


Display the ADBgrandch field addresses
   print own data addr 0x19b207c
   print ancestor data addr 0x19b2078
   print child data addr 0x19b2074
   print base data addr 0x19b2070
   print this object addr 0x19b2060
      contents of memory at 'this' addr 402790
                contents at ^that^ addr 4013ac
                contents at ^that^ addr e5894855
      contents of memory at this++ addr (0x19b2068) ffffffff
      contents of memory at this+2x addr (0x19b2070) 0
      contents of memory at this+3x addr (0x19b2078) d
      contents of memory at this+4x addr (0x19b2080) 333231
      contents of memory at this+5x addr (0x19b2088) 1
      contents of memory at this+6x addr (0x19b2090) 34
      contents of memory at this+7x addr (0x19b2098) 35
      contents of memory at this+8x addr (0x19b20a0) 0
   print size of this object 72
And investigating field locations/alignments
  c1 0x19b2080, c2 0x19b2081, c3 0x19b2082
  s1 0x19b2084, L1 0x19b2088, c4 0x19b2090
  i1 0x19b2094, c5 0x19b2098, d1 0x19b20a0

Examples of instance locations:
   global variable: 0x603400
   global constant: 0x603448
   local variable: 0x7ffc0f183c60
   local constant: 0x7ffc0f183d00
   static local variable: 0x603480
   static local constant: 0x6034c8
   heap dynamic: 0x19b2010

Grandchild object locations:
   static local s: 0x603480
   global globGC: 0x603400
   local g: 0x7ffc0f183c60
   local h: 0x7ffc0f183cb0
   heap dynamic dynGC: 0x19b2010
   abstr heap dynamic absGC: 0x19b2060

Note that main's argc param is at 0x7ffc0f183c5c, local init is at 0x7ffc0f183d08
global TestConst 0x40277c, global TestGlobal 0x6032c0

Locations of abstract base constant as accessed through different objects
   through static local s: 0x603488
   through local g: 0x7ffc0f183c68
   through local h: 0x7ffc0f183cb8
   through global globGC: 0x603408
   through heap dynamic: 0x19b2018
   through heap dynamic + abst base ptr: 0x19b2068
Location of static abstract base constant 0x401ac8

About to call examineParams, g passed by ref, h by value
AbstDynBase constructor call number 6
running grandchild copy constructor

Inside examineParams, param locations 0x7ffc0f183c60, 0x7ffc0f183d10
   sizes 72, 72
   values 0x402790, 0x402790
loc of local ptr2 0x7ffc0f183c30, contents there 0x7ffc0f183d10
   up 8 bytes 0x7ffc0f183c38, 0x7ffc0f183c38
   up another 8 0x7ffc0f183c40, 0x7ffc0f183d80
   up another 8 0x7ffc0f183c48, 0x40106a
   up another 8 0x7ffc0f183c50, 0x7ffc0f183e68
   up another 8 0x7ffc0f183c58, 0x100000000
   up another 8 0x7ffc0f183c60, 0x402790
   up another 8 0x7ffc0f183c68, 0xffffffffffffffff
   up another 8 0x7ffc0f183c70, 0xffffffff00000000
   up another 8 0x7ffc0f183c78, 0xd
ADBgrandch destructor, data is 1

Checking/setting ADBchild class static variables through static method
   default 0x6032c8, 2
   AbstDynBase::shared 0x6032c4, value 1
   ADBchild::shared 0x6032c8, value 2

Checking/setting ADBchild class static variables through static method
   default 0x6032c8, -5
   AbstDynBase::shared 0x6032c4, value 5
   ADBchild::shared 0x6032c8, value -5
ADBgrandch destructor, data is 1
ADBgrandch destructor, data is 0
ADBgrandch destructor, data is -1
ADBgrandch destructor, data is 100
assign6e.txt
#include <cstdio>

class foo {
   public:
      foo();
      ~foo();
      void inlineprint() {
INLILOC:
         printf("Start of inlineprint %p\n", &&INLILOC);
      }
      void print();
};

void testfunc();

int main()
{
MAINLOC:
   printf("Start of main %p\n", &&MAINLOC);
   foo f;
   f.print();
   f.inlineprint();
   testfunc();
}

void testfunc()
{
TESTLOC:
   printf("Start of test function %p\n", &&TESTLOC);
   foo g;
   g.print();
   g.inlineprint();
}

foo::foo()
{
FOOLOC:
   printf("Start of foo constructor %p\n", &&FOOLOC);
}

foo::~foo()
{
FOODLOC:
   printf("Start of foo destructor %p\n", &&FOODLOC);
}

void foo::print()
{
PRINLOC:
   printf("Start of print method %p\n", &&PRINLOC);
}
assign6e.txt
Start of main 0x4006e5
Start of foo constructor 0x4007d6
Start of print method 0x40081a
Start of inlineprint 0x40083c
Start of test function 0x400761
Start of foo constructor 0x4007d6
Start of print method 0x40081a
Start of inlineprint 0x40083c
Start of foo destructor 0x4007f8
Start of foo destructor 0x4007f8