LINUX.ORG.RU

Простой вопрос по C++ : ODR violation


0

0

Hello!

Есть код:

//////////// a.hpp //////////////////
#ifndef __a__
#define __a__

class C
{
  public:
    void foo();
};

void C::foo()
{

}

#endif
//////////// test.cpp //////////////////
#include "a.hpp"

void bar()
{
  C c;
  c.foo();
}
//////////// main.cpp //////////////////
#include "a.hpp"

int main()
{
  C c;
  c.foo();
  return 0;
}
//////////// Makefile //////////////////
all: test.o
        g++ main.cpp test.o

test.o:
        g++ -c test.cpp
clean:
        rm test.o
        a.out
////////////////////////////////////////

При линковке получаю ошибки:

g++ -c test.cpp
g++ main.cpp test.o
test.o: In function `C::foo()':
test.cpp:(.text+0x0): multiple definition of `C::foo()'
/tmp/ccMAE1jz.o:main.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: *** [all] Ошибка 1

Почему получается множественное определение?
В чём принципиальное отличие от случая:

//////////// a.hpp //////////////////
#ifndef __a__
#define __a__

class C
{
  public:
    void foo()
      {

      }
};


#endif
////////////////////////////////////////

при котором всё линкуется нормально?

Спасибо!
anonymous

И почему работает, если объявить foo включаемой:

class C
{
  public:
    inline void foo();
};

anonymous
()
Ответ на: комментарий от anonymous

> В чём принципиальное отличие от случая:
> class C
> {
>   public:
>     void foo()
>       {

тут неявный inline


> И почему работает, если объявить foo включаемой:

потому что inline можно много раз определять -- иначе инлайнами было бы невозможно пользоваться

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

> потому что inline можно много раз определять

в разных единицах трансляции

dilmah ★★★★★
()
Ответ на: комментарий от dilmah

Странно, но я думал, что inline - это лишь рекомендация 
компилятору.
Например, если метод очень большой и тяжелый, то он не будет 
встроенным.
Что же получается - если бы foo был гигантским, то была бы
ошибка multiple definition?
Или к implicit inline это не относится?

anonymous
()
Ответ на: комментарий от anonymous

> Странно, но я думал, что inline - это лишь рекомендация компилятору.

это рекомендация, но она отражается в разных правилах

> Например, если метод очень большой и тяжелый, то он не будет встроенным. Что же получается - если бы foo был гигантским, то была бы ошибка multiple definition?

он не будет встроенным. Но ошибки не будет. Это проблема компилятора гарантировать что ее не будет. В разных компонентах трансляции просто будет свой экземпляр этой функции с неэкспортируемым именем

dilmah ★★★★★
()

а вы мыслено заинклюдьте дефайны... получим в двух обектниках функции с одинаковым именем... Мож в этом причина?

anonymous
()

Вы не видите разницы между _описанием_ и _определением_. "В программе на языке С++ должно быть только одно определение каждого имени, но описаний может быть много". Так же описание может одновременно являться и определением.

Если говорить про методы класса то заголовок метода внутри описания класса - это описание метода, само тело метода - это его определение и оно должно быть в единичном экземпляре (вы же, инклудя его в два файла - создали два тела). Когда и тело метода описано внутри класса - это описание с определением, а когда описание метода соответствует двум определениям - это ошибка =)

ps: перечитайте книжку по С++. можно несколько раз.

Eshkin_kot ★★
()
Ответ на: комментарий от Eshkin_kot

твое объяснение не имеет отношения к вопросу автора

dilmah ★★★★★
()
Ответ на: комментарий от Eshkin_kot

> _описанием_ и _определением_.
даже я не с первого раза понял о чем речь, под '_описанием_' видимо
имелось ввиду объявление.

> Если говорить про методы класса 
В С++ так же нет понятия 'методы класса'

> ps: перечитайте книжку по С++. можно несколько раз.
Не те книжки читаете :)

aton
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.