Each program's code and resulting output are appended further below.
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).
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.
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.
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 |