2016-03-22 5 views
3

EDIT: правильные имена функций, и добавил #pragma разИнициализация переменных в заголовке C++

Это очень сильное упрощение моей проблемы, но если я это сделать:

Ах

#pragma once 
static int testNumber = 10; 
void changeTestNumber(); 

a.cpp

#pragma once 
#include "A.h" 

void changeTestNumber() 
{ 
    testNumber = 15; 
} 

Bh

#pragma once 
#include "A.h" 
// some other stuff 

B.cpp

#pragma once 
#include "B.h" 
// some other stuff 

main.cpp

#pragma once 
#include "B.h" 
#include <iostream> 

int main(){ 

changeTestNumber(); 
std::cout<<testNumber<<std::endl; 

return 0; 
} 

Почему я не получаю testNumber = 15 при вызове из? Что происходит, когда я использую функцию, включенную в заголовок моего включенного заголовка? Если я удаляю статические in from from int testNumber, я получу некоторую ошибку в том, что мой testNumber инициализируется дважды.

Так мой заголовок скомпилирован дважды, когда я это делаю?

Заранее благодарен!

+1

Одна функция называется «changeNumber» (ваш прототип), а другая называется «changeTestNumber» (определение) – Goodies

+0

http://stackoverflow.com/questions/1164167/variable-declaration-in-a-header-file – kkhipis

+0

TL; DR: Да, есть несколько переменных «testNumber», по одному для каждого заголовка. Обычно разработчики ставят статику в файл cpp и используют «#pragma once», чтобы контролировать, сколько раз заголовок определяет его значения. Более подробную информацию о многих применениях «статических» можно найти на этом сайте: http://stackoverflow.com/questions/15235526/the-static-keyword-and-its-various-uses-in-c –

ответ

5

Помимо очевидного неправильного наименования (я предполагаю, что это просто вопрос поспешного создания аналогичного примера и не является фактической проблемой в вашем коде), вам нужно объявить переменную как extern в вашем .h/.hpp файл. Вы не можете иметь переменную extern, которая также является static, поскольку использование (одно из) использования (0) static заключается в сохранении переменной, содержащейся в одном файле .cpp.

Если вы меняете:

static int testNumber = 10; 

в файле A.h на:

extern int testNumber; 

, а затем в файле A.cpp сделать что-то вроде:

#include "A.h" 
int testNumber = 10; 

Теперь идти вперед и бежать :

int main() { 
    //changeNumber(); 
    std::cout << testNumber << std::endl; // prints 10 
    changeTestNumber(); // changes to 15 
    std::cout << testNumber << std::endl; // prints 15 
    std::cin.ignore(); 
    return 0; 
} 

Обязательно исправьте имена функций!

+0

Много хороших ответов здесь, спасибо! Это сработало :) У меня проблемы с этим сейчас для векторов, но я попробую больше, когда у меня будет время, прежде чем я начну спрашивать. – remi000

1

хиджры

extern int testNumber; 
void changeNumber(); 

a.cpp

#include "A.h" 

int testNumber = 10; 

void changeTestNumber() 
{ 
    testNumber = 15; 
} 

B.h

#include "A.h" 
// some other stuff 

B.cpp

#include "B.h" 
// some other stuff 

main.cp р

#include "B.h" 
#include <iostream> 

int main(){ 

    changeTestNumber(); 
    std::cout<<testNumber<<std::endl; 

    return 0; 

}

Пожалуйста, попробуйте, как это.

+0

Много хороших ответов здесь, спасибо! Это сработало :) У меня проблемы с этим сейчас для векторов, но я попробую больше, когда у меня будет время, прежде чем я начну спрашивать. – remi000

3

Goodies и другие, конечно, правильно, но позвольте мне поставить еще один шаг вперед:

  1. static делает определение локальной по отношению к единице трансляции. Таким образом, определение статической глобальной переменной в заголовке приведет к тому, что будет столько копий, сколько единиц перевода. Если это специально не то, что вы хотите, это не так.

  2. extern сообщает компилятору, что глобальная переменная существует где-то, но не определена и должна быть найдена в фазе связи. Чтобы добиться успеха в компоновщике, вам нужно определить его где-нибудь (обычно это исходный файл, где имеет смысл существовать)

  3. Опуская оба из них приведет к ошибке компоновщика «множественного определения», где более одного источника включает заголовок.

Теперь 2 й случай имеет два ограничения:

  • это заставляет вас иметь компилируемый источник для создания экземпляра глобального объекта даже в случае, если вы предоставляете библиотеку шаблонов (или библиотека «только для заголовков»), делая доставку более сложной по мере необходимости
  • Он выдает глобальную фиаско инициализации : если вы инициализируете глобальный объект со значениями, взятыми из других глобальных объектов, определенных в другом месте, поскольку C++ doe не сообщать о порядке их строительства (что в конечном итоге относится к способу работы компоновщика), у вас могут возникнуть проблемы при правильной инициализации и уничтожении глобальных объектов.

Чтобы избежать всего этого, считают, что

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

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

inline int& global_val() //note the & 
{ static int z = 0; return z; } 

единственный недостаток является то, что вы всегда должны поместить () на каждом доступе.

Поскольку локальное значение уникально и создается при вызове, это гарантирует, что если есть зависимости между глобальными (думаю, int z=0 как int z=something_else()), они будут созданы в том порядке, в котором они необходимы и будут уничтожены в обратном порядке, даже в случае рекурсии и нескольких потоков (начиная с C++ 14)

Учитывая эволюцию C++ в отношении дженериков и функциональных парадигм и учитывая, что размещение всех источников в одной единице компиляции иногда предпочтительнее, чем связывание многих источников. . Подумайте о том, чтобы не использовать глобальные переменные, но заменив их на встроенный instatiator функций.

+0

Спасибо за полезные объяснения, оцените это :) – remi000

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