Как вы определяете глобальную функцию в C++?

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

Я предполагаю, что мне придется #include заголовочный файл, в котором объявлена ​​функция, но я не знаю, где определить такую ​​глобальную функцию.

Есть ли веские причины против такой функции?


person Cory Klein    schedule 29.07.2011    source источник


Ответы (6)


вам нужно тело (в файле cpp):

int foo()
{
    return 1;
}

и определение/прототип в заголовочном файле, который будет включен перед любым использованием функции:

#ifndef MY_FOO_HEADER_
#define MY_FOO_HEADER_
    int foo();
#endif

затем использовать его в другом месте:

#include foo.h
void do_some_work()
{
    int bar = foo();
}

или используйте встроенную функцию (не гарантирует, что она будет встроенной, но полезна для небольших функций, таких как foo):

#ifndef MY_FOO_HEADER_
#define MY_FOO_HEADER_
    inline int foo()
    {
        return 1;
    }
#endif

в качестве альтернативы вы можете злоупотреблять функциями на основе заголовков в стиле C (так что это идет в заголовке, static заставляет его существовать только в одной единице компиляции, однако вам следует избегать этого):

#ifndef MY_FOO_HEADER_
#define MY_FOO_HEADER_
    static int foo()
    {
        return 1;
    }
#endif
person Necrolis    schedule 29.07.2011
comment
Почему вам следует избегать использования static, чтобы заставить функцию существовать только в одной единице компиляции? - person HelloGoodbye; 16.05.2013
comment
@HelloGoodbye: «статический» обычно вызывает много путаницы, особенно. статические глобальные функции, это может привести к нежелательному поведению или неправильному использованию, что более важно, если вы используете C++, то вы должны кодировать на C++, что означает использование заголовка с прототипом (который, возможно, помечен как extern) и исходный файл с реализацией это также приносит некоторые полезные побочные эффекты благодаря способу обработки заголовков. - person Necrolis; 16.05.2013
comment
@Necrolis Ты спас меня от неприятностей. Я перешел по этой ссылке, которая была намного длиннее и содержала то же решение, которое вы дали. У вас все четко и лаконично. ценится - person JohnJohn; 12.01.2015
comment
@Necrolis: неправильно ли использовать extern, когда функция была объявлена ​​​​и определена в другом cpp-файле, но доступна? Или это нормально? внешний вид foo(); Он отлично компилируется, но ваше объяснение имеет гораздо больше смысла :-) - person Wim; 17.08.2015
comment
@Wim: AFAIK, extern лишний, за исключением шаблонов (см. Внешний шаблон С++ 11) - person Necrolis; 17.08.2015
comment
@Necrolis: спасибо за быстрый ответ, я исправлю это в своем коде :-) - person Wim; 18.08.2015

То, что вы называете глобальной функцией, обычно называется свободной функцией, и они Хорошая вещь.

Вы бы определили его так же, как функцию-член класса, но за пределами этого класса.

double squared(double x) {
    return x*x;
}

Простые функции, которые вы можете определить с помощью ключевого слова inline в заголовочном файле или просто объявить его там

double squared(double x);

и поместите реализацию (первый пример) в файл *.cpp.

person Benjamin Bannier    schedule 29.07.2011

В заголовочном файле:

// someheader.h
#ifndef MY_GLOBAL_FUN
#define MY_GLOBAL_FUN

void my_global_fun();    

#endif

В файле реализации:

#include "someheader.h"

void my_global_fun()
{
    // ...
}

В других файлах, которым требуется эта функция:

#include "someheader.h"

void f()
{
    my_global_fun();
}

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

person Chad    schedule 29.07.2011
comment
Я все еще получаю сообщение об ошибке «Неопределенные символы» для my_global_fun(), и я настроил свои файлы именно так, как вы показали. Можете ли вы убедиться, что этот код работает для вас? Из всех ответов на эту тему на SO я считаю, что ваш имеет наибольший смысл. - person Clay Ellis; 20.09.2015
comment
Есть много причин, по которым это может не сработать. Какую платформу, компилятор и команду (для сборки) вы используете? - person Chad; 21.09.2015

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

Помните, что в C не было классов, а структуры не могли содержать функции-члены. В бесплатных функциях не было ничего плохого тогда и нет сейчас.

person MGZero    schedule 29.07.2011

Вы должны объявить его прототип в заголовочном файле и определить его в файле реализации.

//file.h
void foo();

//file.cpp
void foo ()
{}

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

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

person iammilind    schedule 29.07.2011

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

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

person Utkarsh Bhardwaj    schedule 24.12.2015