Лучший способ реализовать глобально ограниченные по объему данные

Я хотел бы сделать данные всей программы в программе C++, не сталкиваясь с противными ошибками LNK2005 когда все исходные файлы #includes этот "файл" репозитория глобальной переменной.

У меня есть 2 способа сделать это в C++, и я спрашиваю, какой путь лучше.

Самый легкий способ сделать это в C# - просто общедоступные статические участники.

C#:

public static class DataContainer
{
    public static Object data1 ;
    public static Object data2 ;
}

В C++ можно сделать то же самое

C++ глобальные данные way#1:

class DataContainer
{
public:
    static Object data1 ;
    static Object data2 ;
} ;
Object DataContainer::data1 ;
Object DataContainer::data2 ;

Однако существует также экстерн

C++ глобальная магистраль данных № 2:

class DataContainer
{
public:
    Object data1 ;
    Object data2 ;
} ;
extern DataContainer * dataContainer ; // instantiate in .cpp file

В C++, который лучше, или возможно иначе, о котором я не думал?

Решение уже не должно вызывать LNK2005 "объект определенные" ошибки.

9
задан Brian Tompsett - 汤莱恩 21 November 2015 в 17:01
поделиться

6 ответов

Если вам абсолютно необходимо иметь глобальные объектов, то самый простой способ - просто объявить их 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();
}
12
ответ дан 4 December 2019 в 08:00
поделиться

Лучше всего поместить ваши объекты в пространство имен.

// 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) каждый объект.

8
ответ дан 4 December 2019 в 08:00
поделиться

Общедоступные статические переменные - это просто глобальные переменные, а глобальные переменные - это плохо. Если объект зависит от некоторых данных, которые вы хотите сделать глобальными, создайте сеттер для этой зависимости и создайте своего рода «фабричный» класс, который будет собирать ваше приложение из небольших независимых частей, предоставляя глобальные зависимости через сеттеры. Подобно этому, в псевдокоде:

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.

См. Отличную серию сообщений в блоге Мишко Хевери о синглтонах - вы можете начать с Синглтоны - патологические лжецы и переходить по ссылкам оттуда. .

3
ответ дан 4 December 2019 в 08:00
поделиться

ПОЦЕЛУЙ.

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
1
ответ дан 4 December 2019 в 08:00
поделиться

В файле заголовка (я назову его 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;
}
1
ответ дан 4 December 2019 в 08:00
поделиться

Вы запутались. Ваша проблема ("LNK2005") связана со связью, а не со скопингом на уровне исходного языка. C# смешивает эти вещи (хотя я не думаю, что это обязательно плохо) гораздо больше, чем C++ (но C++ тоже делает это в некоторой степени, например, ключевое слово extern). Ни одно решение этой проблемы не будет жить полностью в сфере компилятора и препроцессора. В игру вступает компоновщик и то, как вы собираете свою программу.

Оба ваших решения фактически используют extern (внешнее связывание) для решения проблемы, просто в первом случае оно неявное. Действительно, данные "в масштабах программы" довольно расплывчаты. Вы имеете в виду "в масштабах всего процесса"? Или общие для всех экземпляров программы? Судя по сообщению об ошибке, я предполагаю, что вы имеете дело с окнами. Использует ли ваша программа библиотеки DLL? Должны ли эти "общепрограммные" данные быть или должны быть общими для разных DLL?

2
ответ дан 4 December 2019 в 08:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: