Пространства имен с внешней связью - PullRequest
6 голосов
/ 02 октября 2009

Проблема, с которой я столкнулся, в основном та же, что упоминается в «greentype» http://www.cplusplus.com/forum/beginner/12458/

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

Рассмотрим следующий пример, где я хочу передать переменную 'i', определенную в основном коде функции a ():


* nn.h: *

#ifndef _NN_H_
#define _NN_H_

namespace nn {
int i;
}
#endif

* main.cpp *

#include <iostream>
#include "nn.h"
using namespace std;
using namespace nn;

void a();

int main()
{
i=5;
a();
}

void a()
{
using namespace std;
using namespace nn;

i++;
cout << "i = " << i << endl;
}

Но теперь, если я помещу определение () в отдельный файл ...


* a.cpp *

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

void a()
{
using namespace std;
using namespace nn;

i++;
cout << "i = " << i << endl;
}

... тогда я получаю ошибку 'множественное определение' при линковке (g ++ main.cpp a.cpp -o main). Если я сделаю объявление 'i' в заголовочном файле 'extern' (как предлагается на других форумах), я получаю ошибку «неопределенная ссылка». Я могу скомпилировать, когда 'i' объявлено как const в заголовке, но это не то, что я хочу.

Любые предложения с благодарностью.

Ответы [ 3 ]

13 голосов
/ 02 октября 2009

Любой глобальный объект, такой как i, должен иметь где-то в программе ровно одно определение, но он может быть объявлен несколько раз.

Использование extern без инициализатора делает объявление просто декларацией. Это подходит для вашего заголовочного файла, но вы все равно должны где-то определить i. Помимо объявления заголовка extern вам также необходимо добавить определение (то есть копию объявления без extern) в один и только один из ваших исходных файлов.

Редактировать: Читая ваш вопрос, вы говорите, что хотите передать переменную в функцию. С точки зрения стиля и структуры кода это обычно не является хорошей причиной для использования общей (глобальной) переменной. При отсутствии каких-либо основополагающих причин вы обычно должны определить функцию, которая принимает параметр и передает значение (возможно, из локальной переменной) с вызывающего сайта в эту функцию через его параметр.

10 голосов
/ 02 октября 2009

Файл заголовка должен сказать:

namespace nn {
    extern int i;
}

Это «декларация», а не «определение». Затем вам нужно определение в одном и только одном файле:

namespace nn {
    int i = 1;
}

Конечно, гораздо лучше - просто не иметь глобалов.

2 голосов
/ 02 октября 2009

Это не имеет ничего общего с пространствами имен, и все это связано со связью, внешней или иным образом символа i в ваших различных примерах. По умолчанию глобальные переменные имеют extern связь, а глобальные const символы имеют static связь - это объясняет, почему это работает, когда вы делаете i const. Чтобы решить вашу проблему, одним из способов является объявление i с внешней связью в заголовочном файле, затем определение только в одном из файлов реализации, как показано ниже:

Заголовок:

extern int i;

a.c:

int i:

main.c:

int main()
{
  i = 1; // or whatever
}

Обратите внимание, что я убрал пространство имен для ясности - конечный результат тот же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...