Лучший способ реализовать данные в глобальном масштабе - PullRequest
9 голосов
/ 20 марта 2010

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

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

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

C #:

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

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

C ++ глобальный способ передачи данных # 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 "объект уже определен".

Ответы [ 6 ]

12 голосов
/ 20 марта 2010

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

Ваш способ # 1 использует класс только с static членами, что означает, что он по сути выполняет работу с пространством имен, так почему бы просто не использовать пространство имен?

Способ № 2 агрегирует оба объекта в одном классе, но если между двумя объектами нет истинной взаимозависимости, особого преимущества для этого нет.

Я бы рекомендовал поместить объекты в namespace для предотвращения загрязнения глобального пространства имен потенциально общими идентификаторами, такими как 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();
}
8 голосов
/ 20 марта 2010

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

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

3 голосов
/ 20 марта 2010

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

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.

Посмотрите отличную серию сообщений в блоге Miško Hevery о синглетонах - вы можете начать с Синглеты - это патологические лжецы и следоватьссылки оттуда.

2 голосов
/ 20 марта 2010

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

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

1 голос
/ 20 марта 2010

ПОЦЕЛУЙ.

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 голос
/ 20 марта 2010

В заголовочном файле (я назову его 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...