• Как трактовать определение в двух разных модулях классов с одинаковым именем?

    EvgenijDv
    @EvgenijDv
    C/C++ programmer
    В общем немного покопавшись нарисовалась вполне ожидаемая ситуация:
    В получившемся исполняемом файле вызывается одна и та же версия метода A::foo()
    objdump -d a.exe
      00401600 <__Z4fooBv>:
      call   402890 <__ZN1A3fooEv>
      
    0040161c <__Z4fooAv>:
      call   402890 <__ZN1A3fooEv>
     
    00401638 <_main>:
      401643:       e8 d4 ff ff ff          call   40161c <__Z4fooAv>
      401648:       e8 b3 ff ff ff          call   401600 <__Z4fooBv>

    После компиляции в объектных файлах используется одно и тоже имя для метода A::foo()
    objdump -t b.o
    
    b.o:     file format pe-i386
    
    SYMBOL TABLE:
    [  0](sec -2)(fl 0x00)(ty   0)(scl 103) (nx 1) 0x00000000 b.cpp
    File
    [  2](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text$_ZN1A3fooEv
    AUX scnlen 0x17 nreloc 2 nlnno 0 checksum 0x0 assoc 0 comdat 2
    [  4](sec  5)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000 __ZN1A3fooEv
    AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
    [  6](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 __Z4fooBv
    
    objdump -t a.o
    
    a.o:     file format pe-i386
    
    SYMBOL TABLE:
    [  0](sec -2)(fl 0x00)(ty   0)(scl 103) (nx 1) 0x00000000 a.cpp
    File
    [  2](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text$_ZN1A3fooEv
    AUX scnlen 0x17 nreloc 2 nlnno 0 checksum 0x0 assoc 0 comdat 2
    [  4](sec  5)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000 __ZN1A3fooEv
    AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
    [  6](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 __Z4fooAv

    Ну и судя по всему, во время линковки, линковщик находит первую реализацию _ZN1A3fooEv и дважды подставляет ее, ведь и в одном и другом объектном файле используется одно и тоже имя. Непонятно только почему он не стал искать вторую реализацию этой функции во втором объектном файле... Может стоит переместить этот вопрос на SO? Я думаю там могут дать более развернутый ответ.
    Ответ написан
    2 комментария
  • Какой смысл внешней компоновки имени класса в C++?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Но у меня сразу возникает мысль. Если компоновка имени внешняя, то это значит, что это имя доступно в других единицах трансляции. Однако, как с функциями не работает:
    foo.cpp
    ----------
    void foo() {}
    
    
    bar.cpp
    ----------
    void foo();
    
    void bar()
    {
       foo();
    }

    Почему же? Работает.

    То есть я не могу написать так:
    A.cpp
    ----------
    class A
    {
    };
    
    
    B.cpp
    ----------
    class A;
    
    void foo(A a) // A is an incomplete type
    {
    }


    Но этот пример не имеет никакого отношения к компоновке имени A. Вы не можете написать так, потому что операция передачи по значению недоступна для неполного типа. Но уже вот так вполне можно написать:

    A.cpp
    ----------
    class A
    {
    };
    
    
    B.cpp
    ----------
    class A;
    
    void foo(A& a) // A is an incomplete type, but who cares
    {
    }


    Вопрос: какой смысл тогда во внешней компоновке имени класса?

    Смысл тот, что имя класса (полное, со всеми неймспейсами) обозначает единственную сущность во всех единицах трансляции одной программы.
    Ответ написан
    Комментировать