Пример C
bb.c:
#include "bb.h"#include <stdio.h>
void bb() {
printf("aa()...\n");
aa();
}
main.c:
#include "aa.h"#include "bb.h"
int main(int argc, const char** argv) {
aa();
bb();
return 0;
}
aa.h:
#ifndef aa_h
#define aa_h
#include <stdio.h>
void aa() {
printf("aa()...\n");
}
#endif // aa_h
bb.h:
#ifndef bb_h
#define bb_h
#include "aa.h"
void bb();
#endif // bb_h
C Результат
Скомпилировано с помощью clang main.c bb.c:
duplicate symbol _aa in:
/var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/main-OsFJVB.o
/var/folders/f2/2w4c0_n519g8cd2k6xv66hc80000gn/T/bb-OkcMzn.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Пример C ++
b.cpp:
#include "b.hpp"
void b::do_something_else() {
std::cout << "b::do_something_else() being called..." << std::endl;
a a;
a.doit();
}
main.cpp:
#include "a.hpp"#include "b.hpp"
int main() {
a a;
b b;
a.doit();
b.do_something_else();
return 0;
}
a.hpp:
#ifndef a_hpp
#define a_hpp
#include <iostream>
class a{
public:
void doit() {
std::cout << "a::doit() being called..." << std::endl;
}
};
#endif // a_hpp
b.hpp:
#ifndef b_hpp
#define b_hpp
#include "a.hpp"
#include <iostream>
class b{
public:
void do_something_else();
};
#endif // b_hpp
C ++ Результат
Вышеуказанное компилируется нормально с clang++ main.cpp b.cpp
и вывод в программу:
a::doit() being called...
b::do_something_else() being called...
a::doit() being called...
Вопросы
Почему дубликат ошибки не происходит с версией C ++?
Имеет ли тот факт, что функция void a::doit()
является определенный в заголовочном файле, а не в исходном файле означает, что компилятор автоматически встроит функцию?
В C ++ методы класса не являются символами верхнего уровня, но являются именами в рамках своей иерархии классов.
Это означает, что вы определили в C ++ два doit()
методы, a::doit()
а также b::doit()
В C вы пытались определить один aa()
функционировать дважды.
Обратите внимание, что C ++ также выдаст ошибку, если вы определите doit()
метод дважды, в рамках того же класса.
#include <iostream>
class a {
public:
void doit() {
std::cout << "hello" << std::endl;
}
void doit() {
std::cout << "goodbye" << std::endl;
}
};
приводит к
ed.cpp:11:8: error: ‘void a::doit()’ cannot be overloaded
void doit() {
^
ed.cpp:7:8: error: with ‘void a::doit()’
void doit() {
^
Почему дублирующаяся ошибка не возникает в версии C ++?
Потому что нет дублирования. Функции-члены C ++ ограничены классом, в котором они определены. B :: doit () не является дубликатом a :: doit ().
Означает ли тот факт, что функция void a :: doit () определена в заголовочном файле, а не в исходном файле, означает, что компилятор автоматически встроит функцию?
Нет, но это значит, что это возможно.
В вашем C
пример, aa
определяется дважды, что нарушает «одно правило определения». Это было бы одинаково верно, если бы это было C++
,
В вашем C++
пример, a::doit
определяется дважды, но неявно объявляется inline
, Функции-члены, определенные в классе, неявно встроены в [dcl.fct.spec]/3
:
Функция, определенная в определении класса, является встроенной функцией. …
inline
функции являются исключением из одного правила определения (на самом деле, это единственный смысл inline
требуется стандартом) в соответствии [basic.def.odr]/5
,
В программе может быть несколько определений встроенной функции … с внешней связью (7.1.2) … при условии, что каждое определение появляется в другой единице перевода, и при условии, что определения удовлетворяют следующим требованиям. …
Требования в основном сводятся к требованию, чтобы определения были идентичны в каждой единице перевода, где они появляются.
Если бы вы заявили aa
как inline
Аналогичные правила были бы применены, и ваш код скомпилировался бы и работал как ожидалось.