Почему функции-члены C ++, определенные в классе, не создают повторяющихся символов, тогда как в C?

Пример 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...

Вопросы

  1. Почему дубликат ошибки не происходит с версией C ++?

  2. Имеет ли тот факт, что функция void a::doit() является определенный в заголовочном файле, а не в исходном файле означает, что компилятор автоматически встроит функцию?

1

Решение

В 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() {
^
2

Другие решения

Почему дублирующаяся ошибка не возникает в версии C ++?

Потому что нет дублирования. Функции-члены C ++ ограничены классом, в котором они определены. B :: doit () не является дубликатом a :: doit ().

Означает ли тот факт, что функция void a :: doit () определена в заголовочном файле, а не в исходном файле, означает, что компилятор автоматически встроит функцию?

Нет, но это значит, что это возможно.

0

В вашем C пример, aa определяется дважды, что нарушает «одно правило определения». Это было бы одинаково верно, если бы это было C++,

В вашем C++ пример, a::doit определяется дважды, но неявно объявляется inline, Функции-члены, определенные в классе, неявно встроены в [dcl.fct.spec]/3:

Функция, определенная в определении класса, является встроенной функцией. …

inline функции являются исключением из одного правила определения (на самом деле, это единственный смысл inline требуется стандартом) в соответствии [basic.def.odr]/5,

В программе может быть несколько определений встроенной функции … с внешней связью (7.1.2) … при условии, что каждое определение появляется в другой единице перевода, и при условии, что определения удовлетворяют следующим требованиям. …

Требования в основном сводятся к требованию, чтобы определения были идентичны в каждой единице перевода, где они появляются.

Если бы вы заявили aa как inlineАналогичные правила были бы применены, и ваш код скомпилировался бы и работал как ожидалось.

0
По вопросам рекламы [email protected]