0

次のプログラムの出力がそのようになっている理由をより深く理解しようとしています (両方については以下を参照)。同時に、それがプログラムのアセンブリ バージョンとどのように関係しているかを理解しようとしています。主に、アセンブリ コード内の型はどこにあり、一方が他方よりも大きくなる原因は何ですか? 子クラスをテストクラスよりも大きくする仮想テーブルの場所は?

コード

#include <iostream>

class parent {
  int glove;
public:
  parent() {}
  virtual ~parent() {}
};

class child : public parent {
  int ball;
public:
  child() {}
  ~child() {}
};

class test {
  int test1;
  int test2;

public:
  test() {}
};

int main() {
  std::cout << "Size of child is " << sizeof(child) << std::endl;
  std::cout << "Size of test is " << sizeof(test) << std::endl;
}

出力

Size of child is 12
Size of test is 8

組み立て

.file   "test.cpp"
    .local  _ZStL8__ioinit
    .comm   _ZStL8__ioinit,1,1
    .section    .rodata
.LC0:
    .string "Size of child is "
.LC1:
    .string "Size of test is "
    .text
.globl main
    .type   main, @function
main:
.LFB974:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $16, %esp
    movl    $.LC0, 4(%esp)
    movl    $_ZSt4cout, (%esp)
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    movl    $12, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEj
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEPFRSoS_E
    movl    $.LC1, 4(%esp)
    movl    $_ZSt4cout, (%esp)
    call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    movl    $8, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEj
    movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
    movl    %eax, (%esp)
    call    _ZNSolsEPFRSoS_E
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE974:
    .size   main, .-main
    .type   _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB984:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $24, %esp
    cmpl    $1, 8(%ebp)
    jne .L5
    cmpl    $65535, 12(%ebp)
    jne .L5
    movl    $_ZStL8__ioinit, (%esp)
    call    _ZNSt8ios_base4InitC1Ev
    movl    $_ZNSt8ios_base4InitD1Ev, %eax
    movl    $__dso_handle, 8(%esp)
    movl    $_ZStL8__ioinit, 4(%esp)
    movl    %eax, (%esp)
    call    __cxa_atexit
.L5:
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE984:
    .size   _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
    .type   _GLOBAL__I_main, @function
_GLOBAL__I_main:
.LFB985:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $24, %esp
    movl    $65535, 4(%esp)
    movl    $1, (%esp)
    call    _Z41__static_initialization_and_destruction_0ii
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE985:
    .size   _GLOBAL__I_main, .-_GLOBAL__I_main
    .section    .ctors,"aw",@progbits
    .align 4
    .long   _GLOBAL__I_main
    .weakref    _ZL20__gthrw_pthread_oncePiPFvvE,pthread_once
    .weakref    _ZL27__gthrw_pthread_getspecificj,pthread_getspecific
    .weakref    _ZL27__gthrw_pthread_setspecificjPKv,pthread_setspecific
    .weakref    _ZL22__gthrw_pthread_createPmPK14pthread_attr_tPFPvS3_ES3_,pthread_create
    .weakref    _ZL20__gthrw_pthread_joinmPPv,pthread_join
    .weakref    _ZL21__gthrw_pthread_equalmm,pthread_equal
    .weakref    _ZL20__gthrw_pthread_selfv,pthread_self
    .weakref    _ZL22__gthrw_pthread_detachm,pthread_detach
    .weakref    _ZL22__gthrw_pthread_cancelm,pthread_cancel
    .weakref    _ZL19__gthrw_sched_yieldv,sched_yield
    .weakref    _ZL26__gthrw_pthread_mutex_lockP15pthread_mutex_t,pthread_mutex_lock
    .weakref    _ZL29__gthrw_pthread_mutex_trylockP15pthread_mutex_t,pthread_mutex_trylock
    .weakref    _ZL31__gthrw_pthread_mutex_timedlockP15pthread_mutex_tPK8timespec,pthread_mutex_timedlock
    .weakref    _ZL28__gthrw_pthread_mutex_unlockP15pthread_mutex_t,pthread_mutex_unlock
    .weakref    _ZL26__gthrw_pthread_mutex_initP15pthread_mutex_tPK19pthread_mutexattr_t,pthread_mutex_init
    .weakref    _ZL29__gthrw_pthread_mutex_destroyP15pthread_mutex_t,pthread_mutex_destroy
    .weakref    _ZL30__gthrw_pthread_cond_broadcastP14pthread_cond_t,pthread_cond_broadcast
    .weakref    _ZL27__gthrw_pthread_cond_signalP14pthread_cond_t,pthread_cond_signal
    .weakref    _ZL25__gthrw_pthread_cond_waitP14pthread_cond_tP15pthread_mutex_t,pthread_cond_wait
    .weakref    _ZL30__gthrw_pthread_cond_timedwaitP14pthread_cond_tP15pthread_mutex_tPK8timespec,pthread_cond_timedwait
    .weakref    _ZL28__gthrw_pthread_cond_destroyP14pthread_cond_t,pthread_cond_destroy
    .weakref    _ZL26__gthrw_pthread_key_createPjPFvPvE,pthread_key_create
    .weakref    _ZL26__gthrw_pthread_key_deletej,pthread_key_delete
    .weakref    _ZL30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t,pthread_mutexattr_init
    .weakref    _ZL33__gthrw_pthread_mutexattr_settypeP19pthread_mutexattr_ti,pthread_mutexattr_settype
    .weakref    _ZL33__gthrw_pthread_mutexattr_destroyP19pthread_mutexattr_t,pthread_mutexattr_destroy
    .ident  "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)"
    .section    .note.GNU-stack,"",@progbits
4

2 に答える 2

2

仮想メソッドのディスパッチは完全に実装の問題です (つまり、コンパイラ固有)。標準は、これがどのように実装されるべきかについて何も述べていません.VTables、黒魔術、または他に何を知っているかを使用することができます.

そうは言っても、何が起こるかは推測するしかありません...

一方が他方よりも大きくなる原因は何ですか?子クラスをテストクラスよりも大きくする仮想テーブルの場所は?

コンパイラが実際に VTable を使用すると仮定すると、それらを実装する通常の方法は、クラスに仮想メソッドがある場合にのみ、VTable への非表示のポインタを各オブジェクトに追加することです (それらが通常のメソッドであるか、クラスのデストラクタであるかは関係ありません)。したがって、parentクラスは実際には次のようになります。

class parent {
  VTable* hidden_vtable_ptr; // this is likely to be why child is bigger than test
  int glove;
public:
  parent() {}
  virtual ~parent() {}
};

仮想デストラクタを使用するか仮想メソッドのみを使用するかにかかわらず、これがどのように発生するかに注意してください。

struct test_pod {
  int t[2];
};
struct test_dtor {
  int t[2];
  virtual ~test_dtor() {}
};
struct test_method {
  int t[2];
  virtual void foo() {}
};

int main() {
  std::cout << sizeof(test_pod) << std::endl;    // 8
  std::cout << sizeof(test_dtor) << std::endl;   // 16
  std::cout << sizeof(test_method) << std::endl; // 16
  return 0;
}
于 2013-05-16T18:32:34.193 に答える