// Checking out the Tape ARchive, a.k.a. TAR file, a.k.a. Tarball. // Note that the archive stores original user and user group names (tea, users) // from the machine on which it was created. Neither of these exist on my machine. oo % tar tvf c++.tar drwxrwxr-x 0 tea users 0 Sep 4 1995 c++example -rw-rw-r-- 0 tea users 187752 Aug 30 1995 c++example/c++.ps -rw-rw-r-- 0 tea users 66890 Sep 4 1995 c++example/c++.tex -rw-r--r-- 0 tea users 3569 Sep 4 1995 c++example/stack.cc -rw------- 0 tea users 3604 Sep 4 1995 c++example/list.cc -rw-r--r-- 0 tea users 1399 Sep 4 1995 c++example/stack.h -rw-r--r-- 0 tea users 3026 Sep 4 1995 c++example/inheritstack.h -rw-r--r-- 0 tea users 6276 Sep 4 1995 c++example/inheritstack.cc -rw------- 0 tea users 919 Sep 4 1995 c++example/list.h -rw-rw-r-- 0 tea users 280 Sep 4 1995 c++example/Makefile -rw------- 0 tea users 1224 Sep 4 1995 c++example/copyright.h -rw-r--r-- 0 tea users 1252 Sep 4 1995 c++example/templatestack.h -rw-r--r-- 0 tea users 3921 Sep 4 1995 c++example/templatestack.cc // That file is a verbatim concatenation of files in the directory, interspersed // with some metadata oo % xxd c++.tar | less oo % xxd c++.tar | tail 00048760: 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d ---------------- 00048770: 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 0a0a 7465 ------------..te 00048780: 6d70 6c61 7465 203c 636c 6173 7320 543e mplate 00048790: 0a53 7461 636b 3c54 3e3a 3a7e 5374 6163 .Stack::~Stac 000487a0: 6b28 2920 7b0a 0a20 2020 2064 656c 6574 k() {.. delet 000487b0: 6520 5b5d 2073 7461 636b 3b0a 7d0a 0a2f e [] stack;.}../ 000487c0: 2f2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d /--------------- 000487d0: 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d ---------------- 000487e0: 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d ---------------- 000487f0: 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d 2d2d ---------------- oo % ls -l c++.tar -rw-r--r-- 1 user staff 296960 Nov 5 14:49 c++.tar // Extract the archive: oo % tar xvf c++.tar x c++example x c++example/c++.ps x c++example/c++.tex x c++example/stack.cc x c++example/list.cc x c++example/stack.h x c++example/inheritstack.h x c++example/inheritstack.cc x c++example/list.h x c++example/Makefile x c++example/copyright.h x c++example/templatestack.h x c++example/templatestack.cc oo % cd c++example c++example % ls Makefile copyright.h list.cc stack.h c++.ps inheritstack.cc list.h templatestack.cc c++.tex inheritstack.h stack.cc templatestack.h // Symbols from a saved previously compiled version: c++example % nm ../c++example.saved/stack 0000000100003de0 s GCC_except_table10 0000000100003df0 s GCC_except_table11 0000000100003e30 s GCC_except_table14 0000000100003e54 s GCC_except_table18 0000000100003e68 s GCC_except_table47 0000000100003e7c s GCC_except_table52 U __Unwind_Resume 0000000100002dec T __ZN5Stack3PopEv // <-- Stack::Pop() 0000000100002dc4 T __ZN5Stack4FullEv // <-- Stack::Full() 0000000100002d54 T __ZN5Stack4PushEi // <-- Stack::Push(int) 0000000100002e50 T __ZN5Stack5EmptyEv 0000000100002e74 T __ZN5Stack8SelfTestEv 0000000100002cb8 T __ZN5StackC1Ei // <-- Stack(int) constructor 0000000100002c28 T __ZN5StackC2Ei // 0000000100002d28 T __ZN5StackD1Ev // <-- ~Stack() destructor 0000000100002cec T __ZN5StackD2Ev // Standard library functions: 0000000100003890 t __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE13__get_pointerEv 0000000100003910 t __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE18__get_long_pointerEv 0000000100003938 t __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE19__get_short_pointerEv 000000010000366c t __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4dataEv 00000001000038dc t __ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE9__is_longEv 00000001000031e4 t __ZNKSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentrycvbEv 0000000100003960 t __ZNKSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_E5firstEv 0000000100003500 t __ZNKSt3__119ostreambuf_iteratorIcNS_11char_traitsIcEEE6failedEv 0000000100003984 t __ZNKSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EE5__getEv 0000000100003b58 t __ZNKSt3__15ctypeIcE5widenEc U __ZNKSt3__16locale9use_facetERNS0_2idE 0000000100003488 t __ZNKSt3__18ios_base5flagsEv 0000000100003a5c t __ZNKSt3__18ios_base5rdbufEv 00000001000035dc t __ZNKSt3__18ios_base5widthEv U __ZNKSt3__18ios_base6getlocEv 00000001000034a0 t __ZNKSt3__19basic_iosIcNS_11char_traitsIcEEE4fillEv 0000000100003a38 t __ZNKSt3__19basic_iosIcNS_11char_traitsIcEEE5rdbufEv 0000000100003aa4 t __ZNKSt3__19basic_iosIcNS_11char_traitsIcEEE5widenEc 00000001000035c8 t __ZNKSt3__19nullptr_tcvPT_INS_15basic_streambufIcNS_11char_traitsIcEEEEEEv 0000000100003a74 T __ZNSt3__111char_traitsIcE11eq_int_typeEii 0000000100003a9c T __ZNSt3__111char_traitsIcE3eofEv 00000001000031c0 T __ZNSt3__111char_traitsIcE6lengthEPKc U __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEmc 0000000100003630 t __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1Emc 0000000100003710 t __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC2Emc U __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev U __ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryC1ERS3_ U __ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryD1Ev U __ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEi 0000000100003998 t __ZNSt3__114pointer_traitsIPKcE10pointer_toERS1_ 00000001000035f4 t __ZNSt3__115basic_streambufIcNS_11char_traitsIcEEE5sputnEPKcl 0000000100003868 t __ZNSt3__116__non_trivial_ifILb1ENS_9allocatorIcEEEC2Ev 0000000100003200 t __ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_ 000000010000375c t __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC1INS_18__default_init_tagESA_EEOT_OT0_ 0000000100003798 t __ZNSt3__117__compressed_pairINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repES5_EC2INS_18__default_init_tagESA_EEOT_OT0_ 0000000100003454 t __ZNSt3__119ostreambuf_iteratorIcNS_11char_traitsIcEEEC1ERNS_13basic_ostreamIcS2_EE 00000001000039d0 t __ZNSt3__119ostreambuf_iteratorIcNS_11char_traitsIcEEEC2ERNS_13basic_ostreamIcS2_EE 00000001000037fc t __ZNSt3__122__compressed_pair_elemINS_12basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE5__repELi0ELb0EEC2ENS_18__default_init_tagE 0000000100003810 t __ZNSt3__122__compressed_pair_elemINS_9allocatorIcEELi1ELb1EEC2ENS_18__default_init_tagE 0000000100003000 T __ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m U __ZNSt3__14coutE U __ZNSt3__15ctypeIcE2idE U __ZNSt3__16localeD1Ev U __ZNSt3__18ios_base33__set_badbit_and_consider_rethrowEv U __ZNSt3__18ios_base5clearEj 0000000100003694 t __ZNSt3__18ios_base5widthEl 0000000100003b90 t __ZNSt3__18ios_base8setstateEj 000000010000383c t __ZNSt3__19allocatorIcEC2Ev 0000000100003568 t __ZNSt3__19basic_iosIcNS_11char_traitsIcEEE8setstateEj 00000001000036c0 t __ZNSt3__19nullptr_tC1EMNS0_5__natEi 00000001000036f4 t __ZNSt3__19nullptr_tC2EMNS0_5__natEi 000000010000387c t __ZNSt3__1L12__to_addressIKcEEPT_S3_ 00000001000035a0 t __ZNSt3__1L15__get_nullptr_tEv 00000001000037e8 t __ZNSt3__1L7forwardINS_18__default_init_tagEEEOT_RNS_16remove_referenceIS2_E4typeE 00000001000039bc t __ZNSt3__1L9addressofIKcEEPT_RS2_ 0000000100003b2c t __ZNSt3__1L9use_facetINS_5ctypeIcEEEERKT_RKNS_6localeE 0000000100002f38 T __ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc U __ZSt9terminatev U __ZdaPv U __ZdlPv U __Znam U __Znwm U ___assert_rtn 0000000100003594 t ___clang_call_terminate U ___cxa_begin_catch U ___cxa_call_unexpected U ___cxa_end_catch U ___gxx_personality_v0 00000001000080d0 d __dyld_private 0000000100000000 T __mh_execute_header 0000000100002f80 T _main U _strlen U dyld_stub_binder c++example % nm ../c++example.saved/stack | less // Now we try to make it. A few things have changed between then and now: c++example % make g++ -o stack stack.cc stack.cc:19:10: fatal error: 'iostream.h' file not found #include ^~~~~~~~~~~~ 1 error generated. make: *** [stack] Error 1 // OK, we do -> c++example % make stack g++ -o stack stack.cc In file included from stack.cc:20: ./copyright.h:25:26: warning: conversion from string literal to 'char *' is deprecated [-Wc++11-compat-deprecated-writable-strings] static char *copyright = "Copyright (c) 1992,1993,1995 The Regents of the University of California. All rights reserved."; ^ stack.cc:112:2: error: use of undeclared identifier 'cout'; did you mean 'count'? cout << "pushing " << count << "\n"; ^~~~ count stack.cc:108:9: note: 'count' declared here int count = 17; ^ stack.cc:112:7: error: invalid operands to binary expression ('int' and 'const char [9]') cout << "pushing " << count << "\n"; ~~~~ ^ ~~~~~~~~~~ stack.cc:118:2: error: use of undeclared identifier 'cout'; did you mean 'count'? cout << "popping " << Pop() << "\n"; ^~~~ count stack.cc:108:9: note: 'count' declared here int count = 17; ^ stack.cc:118:7: error: invalid operands to binary expression ('int' and 'const char [9]') cout << "popping " << Pop() << "\n"; ~~~~ ^ ~~~~~~~~~~ 1 warning and 4 errors generated. make: *** [stack] Error 1 // cout is no longer in the main namespace, we must either refer to it as std::cout // or declare "using namespace std;" // In class I mistyped "use" when I meant "using". Errors resulted. Elided here. c++example % make stack g++ -o stack stack.cc In file included from stack.cc:20: ./copyright.h:25:26: warning: conversion from string literal to 'char *' is deprecated [-Wc++11-compat-deprecated-writable-strings] static char *copyright = "Copyright (c) 1992,1993,1995 The Regents of the University of California. All rights reserved."; ^ 1 warning generated. // Another C++ language improvement: since the string literal "Copyright .." is immutable, // the pointer should also be immutable, a "const char*". c++example % make clean rm stack inheritstack templatestack rm: inheritstack: No such file or directory rm: templatestack: No such file or directory make: *** [clean] Error 1 c++example % make stack g++ -o stack stack.cc // Yay! Now make all: c++example % make g++ -Wall -o inheritstack inheritstack.cc list.cc inheritstack.cc:19:10: fatal error: 'iostream.h' file not found #include ^~~~~~~~~~~~ 1 error generated. list.cc:23:11: error: expected unqualified-id const int NULL = 0; ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_null.h:30:15: note: expanded from macro 'NULL' #define NULL __DARWIN_NULL ^ /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types.h:43:23: note: expanded from macro '__DARWIN_NULL' #define __DARWIN_NULL __null ^ // g++ -E will show the results of applying the C preprocessor alone. // There is a collision between macros, best remove the definition of NULL as a macro. c++example % g++ -E list.cc | less c++example % g++ -E list.cc | wc 1531 4147 52343 c++example % wc list.cc 133 483 3607 list.cc // So that was 1400+ LoCs of includes for 133 LoCs of our code. Keep this blow-up in mind. c++example % make g++ -Wall -o inheritstack inheritstack.cc list.cc In file included from inheritstack.cc:22: ./inheritstack.h:86:8: warning: extra tokens at end of #endif directive [-Wextra-tokens] #endif INHERITSTACK_H ^ // inheritstack.cc:17:12: warning: unused variable 'TRUE' [-Wunused-const-variable] const bool TRUE = true; ^ 2 warnings generated. g++ -Wall -o templatestack templatestack.cc templatestack.cc:19:10: fatal error: 'iostream.h' file not found #include ^~~~~~~~~~~~ 1 error generated. make: *** [templatestack] Error 1 // A few more corrections, and then we can make all and test all. c++example % make g++ -Wall -o templatestack templatestack.cc c++example % ./stack pushing 17 pushing 18 pushing 19 pushing 20 pushing 21 pushing 22 pushing 23 pushing 24 pushing 25 pushing 26 popping 26 popping 25 popping 24 popping 23 popping 22 popping 21 popping 20 popping 19 popping 18 popping 17 // Testing example with inheritance: c++example % ./inheritstack Testing ArrayStack pushing 17 pushing 18 pushing 19 pushing 20 pushing 21 pushing 22 pushing 23 pushing 24 pushing 25 pushing 26 popping 26 popping 25 popping 24 popping 23 popping 22 popping 21 popping 20 popping 19 popping 18 popping 17 Testing ListStack pushing 17 pushing 18 pushing 19 pushing 20 pushing 21 pushing 22 pushing 23 pushing 24 pushing 25 pushing 26 popping 26 popping 25 popping 24 popping 23 popping 22 popping 21 popping 20 popping 19 popping 18 popping 17 // Observe that there is only one SelfTest function. It is inherited by both ArrayStack // and ListStack, and compiled so that it runs with both kinds of objects: c++example % nm inheritstack | grep SelfTest 00000001000029d8 T __ZN5Stack8SelfTestEi c++example % lldb ./inheritstack (lldb) target create "./inheritstack" Current executable set to '/Users/user/cs59/oo/c++example/inheritstack' (arm64). (lldb) b main Breakpoint 1: where = inheritstack`main, address = 0x0000000100002b48 (lldb) r Process 90591 launched: '/Users/user/cs59/oo/c++example/inheritstack' (arm64) Process 90591 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100002b48 inheritstack`main inheritstack`main: -> 0x100002b48 <+0>: sub sp, sp, #0x70 ; =0x70 0x100002b4c <+4>: stp x29, x30, [sp, #0x60] 0x100002b50 <+8>: add x29, sp, #0x60 ; =0x60 0x100002b54 <+12>: stur wzr, [x29, #-0x4] Target 0: (inheritstack) stopped. (lldb) disas -n Stack::SelfTest inheritstack`Stack::SelfTest: 0x1000029d8 <+0>: sub sp, sp, #0x40 ; =0x40 0x1000029dc <+4>: stp x29, x30, [sp, #0x30] 0x1000029e0 <+8>: add x29, sp, #0x30 ; =0x30 0x1000029e4 <+12>: stur x0, [x29, #-0x8] 0x1000029e8 <+16>: stur w1, [x29, #-0xc] 0x1000029ec <+20>: ldur x8, [x29, #-0x8] 0x1000029f0 <+24>: str x8, [sp, #0x10] 0x1000029f4 <+28>: mov w8, #0x11 // <-- 17 from the code 0x1000029f8 <+32>: stur w8, [x29, #-0x10] 0x1000029fc <+36>: stur wzr, [x29, #-0x14] 0x100002a00 <+40>: ldur w8, [x29, #-0x14] 0x100002a04 <+44>: ldur w9, [x29, #-0xc] 0x100002a08 <+48>: subs w8, w8, w9 0x100002a0c <+52>: b.ge 0x100002a98 ; <+192> // Note the indirection pattern for the method call, Full() 0x100002a10 <+56>: ldr x0, [sp, #0x10] // pointer to object, default argument 0x100002a14 <+60>: ldr x8, [x0] // load VPTR from the object's struct 0x100002a18 <+64>: ldr x8, [x8, #0x20] // load method address from VTABLE 0x100002a1c <+68>: blr x8 // indirect method call 0x100002a20 <+72>: tbz w0, #0x0, 0x100002a44 ; <+108> 0x100002a24 <+76>: adrp x0, 1 0x100002a28 <+80>: add x0, x0, #0xe11 ; =0xe11 0x100002a2c <+84>: adrp x1, 1 0x100002a30 <+88>: add x1, x1, #0xddf ; =0xddf 0x100002a34 <+92>: mov w2, #0xc8 0x100002a38 <+96>: adrp x3, 1 0x100002a3c <+100>: add x3, x3, #0xdfc ; =0xdfc 0x100002a40 <+104>: bl 0x100003ba0 ; symbol stub for: __assert_rtn 0x100002a44 <+108>: adrp x0, 2 0x100002a48 <+112>: ldr x0, [x0] 0x100002a4c <+116>: adrp x1, 1 0x100002a50 <+120>: add x1, x1, #0xe1a ; =0xe1a 0x100002a54 <+124>: bl 0x100003b58 ; symbol stub for: std::__1::basic_ostream >& std::__1::operator<< >(std::__1::basic_ostream >&, char const*) 0x100002a58 <+128>: ldur w1, [x29, #-0x10] 0x100002a5c <+132>: bl 0x100003b1c ; symbol stub for: std::__1::basic_ostream >::operator<<(int) 0x100002a60 <+136>: adrp x1, 1 0x100002a64 <+140>: add x1, x1, #0xe23 ; =0xe23 0x100002a68 <+144>: bl 0x100003b58 ; symbol stub for: std::__1::basic_ostream >& std::__1::operator<< >(std::__1::basic_ostream >&, char const*) // Another indirect call, Push(count++) : 0x100002a6c <+148>: ldr x0, [sp, #0x10] // object pointer, a.k.a. "this" 0x100002a70 <+152>: ldur w1, [x29, #-0x10] // count++: load count 0x100002a74 <+156>: add w8, w1, #0x1 ; =0x1 // ++ 0x100002a78 <+160>: stur w8, [x29, #-0x10] // store count 0x100002a7c <+164>: ldr x8, [x0] // load VPTR 0x100002a80 <+168>: ldr x8, [x8, #0x10] // load VTABLE pointer to Push 0x100002a84 <+172>: blr x8 // call Push(..) 0x100002a88 <+176>: ldur w8, [x29, #-0x14] 0x100002a8c <+180>: add w8, w8, #0x1 ; =0x1 0x100002a90 <+184>: stur w8, [x29, #-0x14] 0x100002a94 <+188>: b 0x100002a00 ; <+40> 0x100002a98 <+192>: ldr x0, [sp, #0x10] // now calling Empty() 0x100002a9c <+196>: ldr x8, [x0] // VPTR again 0x100002aa0 <+200>: ldr x8, [x8, #0x28] // Empty() 0x100002aa4 <+204>: blr x8 // call it 0x100002aa8 <+208>: tbnz w0, #0x0, 0x100002af4 ; <+284> 0x100002aac <+212>: adrp x0, 2 0x100002ab0 <+216>: ldr x0, [x0] 0x100002ab4 <+220>: adrp x1, 1 0x100002ab8 <+224>: add x1, x1, #0xe25 ; =0xe25 0x100002abc <+228>: bl 0x100003b58 ; symbol stub for: std::__1::basic_ostream >& std::__1::operator<< >(std::__1::basic_ostream >&, char const*) 0x100002ac0 <+232>: mov x1, x0 // Save pointer to cout into x1 0x100002ac4 <+236>: ldr x0, [sp, #0x10] // Load pointer to the Stack object to pop 0x100002ac8 <+240>: str x1, [sp, #0x8] // Save cout pointer to the stack 0x100002acc <+244>: ldr x8, [x0] // Get VPTR 0x100002ad0 <+248>: ldr x8, [x8, #0x18] // Get pointer to Pop() from VTABLE 0x100002ad4 <+252>: blr x8 // call Pop() 0x100002ad8 <+256>: mov x1, x0 // the int popped off the stack 0x100002adc <+260>: ldr x0, [sp, #0x8] // cout stream pointer 0x100002ae0 <+264>: bl 0x100003b1c ; symbol stub for: std::__1::basic_ostream >::operator<<(int) 0x100002ae4 <+268>: adrp x1, 1 0x100002ae8 <+272>: add x1, x1, #0xe23 ; =0xe23 0x100002aec <+276>: bl 0x100003b58 ; symbol stub for: std::__1::basic_ostream >& std::__1::operator<< >(std::__1::basic_ostream >&, char const*) 0x100002af0 <+280>: b 0x100002a98 ; <+192> 0x100002af4 <+284>: ldp x29, x30, [sp, #0x30] 0x100002af8 <+288>: add sp, sp, #0x40 ; =0x40 0x100002afc <+292>: ret (lldb) ^D // Note that the above code works for both ArrayStack and ListStack, because the // right versions of Full(), Push(int), Empty(), and Pop() are lookup up off // of the right object's VPTR at the start of the object ("ldr x8, [x0]") // Another example: oo % g++ -Wall -o inh-min inh-min.cc inh-min.cc:6:11: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int a = 0, b = 0 , c = 0; ^ inh-min.cc:6:18: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int a = 0, b = 0 , c = 0; ^ inh-min.cc:6:26: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int a = 0, b = 0 , c = 0; ^ inh-min.cc:15:11: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int b = 1; ^ 4 warnings generated. // See annotations in inh-annotated.cc about these warnings oo % ./inh-min base derived derived member b via ptr: 0 1 oo % g++ -g -Wall -o inh-min inh-min.cc inh-min.cc:6:11: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int a = 0, b = 0 , c = 0; ^ inh-min.cc:6:18: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int a = 0, b = 0 , c = 0; ^ inh-min.cc:6:26: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int a = 0, b = 0 , c = 0; ^ inh-min.cc:15:11: warning: default member initializer for non-static data member is a C++11 extension [-Wc++11-extensions] int b = 1; ^ 4 warnings generated. oo % lldb inh-min (lldb) target create "inh-min" Current executable set to '/Users/user/cs59/oo/inh-min' (arm64). (lldb) b main Breakpoint 1: where = inh-min`main + 32 at inh-min.cc:31:11, address = 0x0000000100002c8c (lldb) r Process 90842 launched: '/Users/user/cs59/oo/inh-min' (arm64) Process 90842 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100002c8c inh-min`main at inh-min.cc:31:11 28 29 int main() 30 { -> 31 Base b; 32 Derived d; 33 SuperDerived sd; 34 Target 0: (inh-min) stopped. (lldb) list 35 Base* bp = &b; // the type of bp is Base* 36 Derived* dp = &d; // the type of dp is Base* as well 37 bp->f(); // prints "base" 38 dp->f(); // prints "derived" 39 40 bp = &d; 41 (lldb) list 42 bp->f(); // <----- this is the heart of OO! 43 44 //bp = &sd; 45 46 //bp->f(); // <----- this is the heart of OO! 47 48 std::cout << "member b via ptr: " << bp->b << " " << dp->b << std::endl; (lldb) b 42 Breakpoint 2: where = inh-min`main + 112 at inh-min.cc:42:6, address = 0x0000000100002cdc (lldb) cont Process 90842 resuming base derived Process 90842 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 frame #0: 0x0000000100002cdc inh-min`main at inh-min.cc:42:6 39 40 bp = &d; 41 -> 42 bp->f(); // <----- this is the heart of OO! 43 44 //bp = &sd; 45 Target 0: (inh-min) stopped. // We are about to see the call indirection for f(): (lldb) disas -p inh-min`main: -> 0x100002cdc <+112>: ldr x0, [sp, #0x28] 0x100002ce0 <+116>: ldr x8, [x0] 0x100002ce4 <+120>: ldr x8, [x8] // f() is the only method in its class, no offset 0x100002ce8 <+124>: blr x8 (lldb) frame var (Base) b = (a = 0, b = 0, c = 0) (Derived) d = { Base = (a = 0, b = 0, c = 0) b = 1 } (SuperDerived) sd = { Derived = { Base = (a = 0, b = 0, c = 0) b = 1 } } (Derived *) bp = 0x000000016fdff708 (Derived *) dp = 0x000000016fdff708 // Let's see what's at the object pointer bp: (lldb) x/5xg 0x000000016fdff708 0x16fdff708: 0x0000000100004078 0x0000000000000000 ^^^^^^^^^^^^^^^^^^--- VPTR 0x16fdff718: 0x0000000100000000 0x0000000100004050 0x16fdff728: 0x0000000000000000 // Now let's see what VPTR points to: (lldb) x/5xg 0x0000000100004078 0x100004078: 0x0000000100002f40 0x00000001feea29a8 0x100004088: 0x8000000100003e90 0x0000000100004058 0x100004098: 0x0000000000000000 // Sure enough, the first pointer in VTPR-pointed VTABLE is recognized // by the debugger as a pointer to Derived::f(): (lldb) disas -a 0x0000000100002f40 inh-min`Derived::f: // <<--- there 0x100002f40 <+0>: sub sp, sp, #0x20 ; =0x20 0x100002f44 <+4>: stp x29, x30, [sp, #0x10] 0x100002f48 <+8>: add x29, sp, #0x10 ; =0x10 0x100002f4c <+12>: str x0, [sp, #0x8] 0x100002f50 <+16>: adrp x0, 2 0x100002f54 <+20>: ldr x0, [x0] 0x100002f58 <+24>: adrp x1, 1 0x100002f5c <+28>: add x1, x1, #0xe73 ; =0xe73 0x100002f60 <+32>: bl 0x100003c74 ; symbol stub for: std::__1::basic_ostream >& std::__1::operator<< >(std::__1::basic_ostream >&, char const*) 0x100002f64 <+36>: ldp x29, x30, [sp, #0x10] 0x100002f68 <+40>: add sp, sp, #0x20 ; =0x20 0x100002f6c <+44>: ret (lldb) ^D // Another run, to see both Base::f() and Derived::f() oo % lldb inh-min (lldb) target create "inh-min" Current executable set to '/Users/user/cs59/oo/inh-min' (arm64). (lldb) b main Breakpoint 1: where = inh-min`main + 32 at inh-min.cc:31:11, address = 0x0000000100002c8c (lldb) r Process 91116 launched: '/Users/user/cs59/oo/inh-min' (arm64) Process 91116 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100002c8c inh-min`main at inh-min.cc:31:11 28 29 int main() 30 { -> 31 Base b; 32 Derived d; 33 SuperDerived sd; 34 Target 0: (inh-min) stopped. (lldb) list 35 Base* bp = &b; // the type of bp is Base* 36 Derived* dp = &d; // the type of dp is Base* as well 37 bp->f(); // prints "base" 38 dp->f(); // prints "derived" 39 40 bp = &d; 41 (lldb) b 40 Breakpoint 2: where = inh-min`main + 108 at inh-min.cc:40:9, address = 0x0000000100002cd8 (lldb) cont Process 91116 resuming base derived Process 91116 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 frame #0: 0x0000000100002cd8 inh-min`main at inh-min.cc:40:9 37 bp->f(); // prints "base" 38 dp->f(); // prints "derived" 39 -> 40 bp = &d; 41 42 bp->f(); // <----- this is the heart of OO! 43 Target 0: (inh-min) stopped. (lldb) frame va (Base) b = (a = 0, b = 0, c = 0) (Derived) d = { Base = (a = 0, b = 0, c = 0) b = 1 } (SuperDerived) sd = { Derived = { Base = (a = 0, b = 0, c = 0) b = 1 } } (Base *) bp = 0x000000016fdff720 // two different objects (Derived *) dp = 0x000000016fdff708 (lldb) x/5xg 0x000000016fdff720 // Base instance 0x16fdff720: 0x0000000100004050 0x0000000000000000 // a, b, c 0x16fdff730: 0x0000000000000000 0x0000000000000000 // 0x16fdff740: 0x000000016fdff760 (lldb) x/5xg 0x000000016fdff708 // Derived instance 0x16fdff708: 0x0000000100004078 0x0000000000000000 // a, b, c 0x16fdff718: 0x0000000100000000 0x0000000100004050 0x16fdff728: 0x0000000000000000 (lldb) x/5xg 0x0000000100004050 // VPTR to Base's VTABLE 0x100004050: 0x0000000100002ec4 0x00000001feea2940 0x100004060: 0x8000000100003e8a 0x0000000000000000 0x100004070: 0x0000000100004080 (lldb) disas -a 0x0000000100002ec4 // Base::f() pointer! inh-min`Base::f: 0x100002ec4 <+0>: sub sp, sp, #0x20 ; =0x20 0x100002ec8 <+4>: stp x29, x30, [sp, #0x10] 0x100002ecc <+8>: add x29, sp, #0x10 ; =0x10 0x100002ed0 <+12>: str x0, [sp, #0x8] 0x100002ed4 <+16>: adrp x0, 2 0x100002ed8 <+20>: ldr x0, [x0] 0x100002edc <+24>: adrp x1, 1 0x100002ee0 <+28>: add x1, x1, #0xe6d ; =0xe6d 0x100002ee4 <+32>: bl 0x100003c74 ; symbol stub for: std::__1::basic_ostream >& std::__1::operator<< >(std::__1::basic_ostream >&, char const*) 0x100002ee8 <+36>: ldp x29, x30, [sp, #0x10] 0x100002eec <+40>: add sp, sp, #0x20 ; =0x20 0x100002ef0 <+44>: ret // This is not code. In fact, this is a runtime type information (RTTI) entry (lldb) disas -a 0x00000001feea2940 libc++abi.dylib`vtable for __cxxabiv1::__class_type_info: 0x1feea2930 <+0>: udf #0x0 0x1feea2934 <+4>: udf #0x0 0x1feea2938 <+8>: .long 0xfeea2980 ; unknown opcode 0x1feea293c <+12>: udf #0x1 0x1feea2940 <+16>: adrp x28, -1045540 0x1feea2944 <+20>: udf #0x1 0x1feea2948 <+24>: adrp x0, -1045536 0x1feea294c <+28>: udf #0x1 0x1feea2950 <+32>: adrp x16, -1045564 0x1feea2954 <+36>: udf #0x1 0x1feea2958 <+40>: adrp x20, -1045564 0x1feea295c <+44>: udf #0x1 0x1feea2960 <+48>: adrp x16, -1045500 0x1feea2964 <+52>: udf #0x1 0x1feea2968 <+56>: adrp x16, -1044752 0x1feea296c <+60>: udf #0x1 0x1feea2970 <+64>: adrp x4, -1044868 0x1feea2974 <+68>: udf #0x1 0x1feea2978 <+72>: adrp x8, -1045452 0x1feea297c <+76>: udf #0x1 (lldb) x/5xg 0x0000000100004078 // Instance of Derived 0x100004078: 0x0000000100002f40 0x00000001feea29a8 ^^^^^^^^^^^^^^^^^^----------------------VPTR of Derived 0x100004088: 0x8000000100003e90 0x0000000100004058 0x100004098: 0x0000000000000000 (lldb) disas -a 0x0000000100002f40 // Derived::f() inh-min`Derived::f: 0x100002f40 <+0>: sub sp, sp, #0x20 ; =0x20 0x100002f44 <+4>: stp x29, x30, [sp, #0x10] 0x100002f48 <+8>: add x29, sp, #0x10 ; =0x10 0x100002f4c <+12>: str x0, [sp, #0x8] 0x100002f50 <+16>: adrp x0, 2 0x100002f54 <+20>: ldr x0, [x0] 0x100002f58 <+24>: adrp x1, 1 0x100002f5c <+28>: add x1, x1, #0xe73 ; =0xe73 0x100002f60 <+32>: bl 0x100003c74 ; symbol stub for: std::__1::basic_ostream >& std::__1::operator<< >(std::__1::basic_ostream >&, char const*) 0x100002f64 <+36>: ldp x29, x30, [sp, #0x10] 0x100002f68 <+40>: add sp, sp, #0x20 ; =0x20 0x100002f6c <+44>: ret (lldb) ^D // Study the templatestack.h and templatestack.cc example. Note the different // functions generated from the template instantiations: c++example % nm templatestack | grep Push 0000000100003970 T __ZN5StackIcE4PushEc <<-- note Ic, Ec for Stack 000000010000381c T __ZN5StackIiE4PushEi <<-- note Ii, Ei for Stack c++example % nm templatestack | grep Pop 0000000100003a08 T __ZN5StackIcE3PopEv 00000001000038b0 T __ZN5StackIiE3PopEv c++example % nm templatestack | grep Full 0000000100003914 T __ZN5StackIcE4FullEv 00000001000037f4 T __ZN5StackIiE4FullEv c++example % nm templatestack | grep Empty 00000001000039e4 T __ZN5StackIcE5EmptyEv 000000010000388c T __ZN5StackIiE5EmptyEv c++example % nm templatestack | grep SelfTest 00000001000029f4 T __ZN5StackIcE8SelfTestEc 000000010000292c T __ZN5StackIiE8SelfTestEi