Я хотел бы сделать данные всей программы в программе C++, не сталкиваясь с противными ошибками LNK2005 когда все исходные файлы #includes этот "файл" репозитория глобальной переменной.
У меня есть 2 способа сделать это в C++, и я спрашиваю, какой путь лучше.
Самый легкий способ сделать это в C# - просто общедоступные статические участники.
C#:
public static class DataContainer
{
public static Object data1 ;
public static Object data2 ;
}
В C++ можно сделать то же самое
class DataContainer
{
public:
static Object data1 ;
static Object data2 ;
} ;
Object DataContainer::data1 ;
Object DataContainer::data2 ;
Однако существует также экстерн
class DataContainer
{
public:
Object data1 ;
Object data2 ;
} ;
extern DataContainer * dataContainer ; // instantiate in .cpp file
В C++, который лучше, или возможно иначе, о котором я не думал?
Решение уже не должно вызывать LNK2005 "объект определенные" ошибки.
Если вам абсолютно необходимо иметь глобальные объектов, то самый простой способ - просто объявить их extern
в файле заголовка, включенном в любое место, где требуется доступ к ним, и определить их в одном исходном файле.
Ваш способ №1 использует класс только с статическими
членами, что означает, что он, по сути, выполняет работу пространства имен, так почему бы просто не использовать пространство имен?
Способ №2 объединяет оба объекта в один класс, но если нет истинной взаимозависимости между двумя объектами, это не дает особой выгоды.
Я бы рекомендовал поместить объекты в пространство имен
, чтобы предотвратить загрязнение глобального пространства имен потенциально общими идентификаторами, такими как data1
,
// File: globaldata.h
#ifndef GLOBALDATA_H
#define GLOBALDATA_H
#include "Object.h" // Definition of Object might be here
namespace GlobalData
{
extern Object data1;
extern Obejct data2;
}
#endif GLOBALDATA_H
.
// File: globaldata.cc
#include globaldata.h
namespace GlobalData
{
Object data1;
Object data2;
}
Тогда вы сможете получить к ним доступ в других подобных местах.
#include "globaldata.h"
// Does something with global data
void f()
{
GlobalData::data1.doSomething();
}
Лучше всего поместить ваши объекты в пространство имен.
// header
namespace global // or any appropriate name
{
extern Object data1 ;
extern Object data2 ;
}
// cpp
namespace global // or any appropriate name
{
Object data1 ;
Object data2 ;
}
Как указано в комментариях: для этого не забудьте использовать квалификатор extern
для объявлений (в файле заголовка), чтобы указать, что существует только один экземпляр (в файле cpp) каждый объект.
Общедоступные статические переменные - это просто глобальные переменные, а глобальные переменные - это плохо. Если объект зависит от некоторых данных, которые вы хотите сделать глобальными, создайте сеттер для этой зависимости и создайте своего рода «фабричный» класс, который будет собирать ваше приложение из небольших независимых частей, предоставляя глобальные зависимости через сеттеры. Подобно этому, в псевдокоде:
class A:
has dependency1 of type X;
has dependency2 of type Y;
class Factory:
has sharedX of type X;
has sharedY of type Y;
init:
sharedX = createX;
sharedY = createY;
wireApplication:
instanceOfA = createA;
instanceOfA.setDependency1(sharedX);
instanceOfA.setDependency2(sharedY);
return instanceOfA;
Таким образом, зависимости A не жестко запрограммированы путем доступа к статическим переменным. У этого есть несколько преимуществ. Во-первых, они более заметны, поскольку вы не извлекаете тайно информацию из других классов в файле реализации. Во-вторых, они не высечены в камне, потому что вы действительно можете создать A, не перетягивая с его помощью X и Y. В-третьих, у вас есть точный контроль над временем жизни X и Y.
См. Отличную серию сообщений в блоге Мишко Хевери о синглтонах - вы можете начать с Синглтоны - патологические лжецы и переходить по ссылкам оттуда. .
ПОЦЕЛУЙ.
DataContainer.h
#pragma once
namespace DataContainer {
extern Object data1;
extern Object data2;
} // namespace DataContainer
DataContainer.cpp
#include <DataContainer.h>
namespace DataContainer {
Object data1;
Object data2;
}// namespace DataContainer
В файле заголовка (я назову его Data.h):
namespace Data
{
extern Object data1;
extern Object data2;
}
Во всех исходных файлах, которым необходимо знать об этом:
#include "Data.h"
Для Data.cpp вы можете написать либо
#include "Data.h"
Object Data::data1;
Object Data::data1;
, либо
#include "Data.h"
namespace Data
{
Object data1;
Object data2;
}
Вы запутались. Ваша проблема ("LNK2005
") связана со связью, а не со скопингом на уровне исходного языка. C# смешивает эти вещи (хотя я не думаю, что это обязательно плохо) гораздо больше, чем C++ (но C++ тоже делает это в некоторой степени, например, ключевое слово extern
). Ни одно решение этой проблемы не будет жить полностью в сфере компилятора и препроцессора. В игру вступает компоновщик и то, как вы собираете свою программу.
Оба ваших решения фактически используют extern
(внешнее связывание) для решения проблемы, просто в первом случае оно неявное. Действительно, данные "в масштабах программы" довольно расплывчаты. Вы имеете в виду "в масштабах всего процесса"? Или общие для всех экземпляров программы? Судя по сообщению об ошибке, я предполагаю, что вы имеете дело с окнами. Использует ли ваша программа библиотеки DLL? Должны ли эти "общепрограммные" данные быть или должны быть общими для разных DLL?