2017-02-18 101 views
1

Я сделал простой эксперимент, файл «.h» с определением класса и определение Funciton, как показано ниже:Файл заголовка содержит тело функции, приведет к дублированию определения?

$cat testInline.h 
#pragma once 
class C{ 
public: 
    void f(){} 
}; 
void g(){} 

Тогда 2 пользователей этого .h файла:

$cat use01.cpp 
#include"testInline.h" 
void g01(){ 
    g(); 
    C obj1; 
    obj1.f(); 
} 

$cat use02.cpp 
#include"testInline.h" 
int main(){ 
    g(); 
    C obj2; 
    obj2.f(); 
    return 0; 
} 

компилировать их вместе и получает ошибку:

$g++ use01.cpp use02.cpp 
duplicate symbol __Z1gv in: 
    /var/folders/zv/b953j0_55vldj97t0wz4qmkh0000gn/T/use01-34f300.o 
    /var/folders/zv/b953j0_55vldj97t0wz4qmkh0000gn/T/use02-838e05.o 
ld: 1 duplicate symbol for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Выглядит очень странно: Я использовал «#pragma один раз», до сих пор я не могу остановить компилятор сообщать дублированный определение г() (__ Z1gv как имя коверкая)

Тогда я изменил testInline.h-> г (определение), чтобы быть похожим:

inline void g(){} 

Ну, он компилирует. Разве это не на C++, что ключевое слово «inline» в принципе бесполезно, потому что компиляторы решат, будет ли он встроить функцию или нет?

И, почему C :: f() с кодом в файле .h не сообщает о дублировании, а функция C-стиля g()? И почему класс C не «должен» добавить «inline» для своей функции «f()», а g() должен использовать «inline»?

Надеюсь, я четко изложил свой вопрос. Спасибо за вашу помощь.

ответ

3

I've used "#pragma once",

Да, вы сделали. И каждый из двух блоков перевода эффективно обрабатывал заголовочный файл ровно один раз. Каждый из них сделал бы это даже без прагмы, так как каждая единица перевода включала заголовочный файл только один раз.

#pragma once не означает «включить этот заголовочный файл только в одном из единиц перевода, которые скомпилированы». Это означает, что «включать этот заголовочный файл один раз на единицу перевода, даже если блок перевода напрямую или косвенно включает в себя заголовочный файл два или более раз». Таким образом, каждая единица перевода включала заголовочный файл и определяла функции/методы из самого файла заголовка. Поскольку одна и та же функция или метод в конечном итоге определялась обеим единицами перевода, вы получили дубликат во время соединения.

Isn't it in C++ that "inline" keyword is basically useless, because compilers will decide whether it'll inline a function or not?

Верно, что компилятор решает, действительно ли функция встраивается, или нет. Однако ключевое слово inline определяет, обрабатывается ли определение функции, как если бы оно было логически встроено для каждого его использования, а не определено на самом деле. Таким образом, использование ключевого слова inline не приводит к дублированию определений, поскольку логически функция вставлена ​​встроенной в каждую ссылку.

Это правда, что действительно ли это происходит, или же компилятор создает не-встроенный код, зависит от компилятора. Однако C++ требует, чтобы функция компилировалась «как бы», она была встроена; поэтому, даже если компилятор решает не включать функцию, он должен предпринять любые шаги, необходимые для обеспечения того, чтобы дублированные неинтенсивные копии функции не приводили к плохо сформированной программе.

And,why C::f() with code in .h file doesn't report duplication,

Поскольку метод класса определяет внутри определения класса фактически является определение рядного, даже если inline ключевого слова явно не указано.

+0

«C++ требует, чтобы функция скомпилировалась», как будто «она была встроена», рассмотрим рекурсивную функцию. ;-) –

3

Ключевое слово inline не бесполезно. Просто он не обязательно контролирует, действительно ли функция встроена.

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

Функция, определенная в определении класса, например, ваш C::f, автоматически считается «inline».

 Смежные вопросы

  • Нет связанных вопросов^_^