Цель состоит в том, чтобы сохранить одинаковые настройки для всей моей программы. Когда программа запускается, она должна прочитать некоторые текстовые файлы (отредактированные пользователем) и перезаписать соответствующие глобальные переменные. Неотредактированные значения должны сохранять значения по умолчанию.
Сейчас я делаю это, используя два отдельных файла: Settings.h
и DefaultSettings.h
.
В Settings.h
:
#pragma once
#include <string>
namespace Settings {
extern int bits;
extern int k;
extern int nsym;
extern void apply_settings(std::string &name, std::string &value);
}
В DefaultSettings.h
:
#pragma once
#include "Settings.h"
#include <string>
namespace Settings {
int bits = 8;
int k = 20;
int nsym = 12;
// Called one by one by the file reader
void apply_settings(std::string &name, std::string &value) {
if (name == "bits") {
bits = atoi(value.c_str());
} else if (name == "k") {
k = atoi(value.c_str());
} else if (name == "nsym") {
nsym = atoi(value.c_str());
}
}
}
Позже в программе, после прочтения и применения настроек, я создаю экземпляры класса и использую их следующим образом:
#pragma once
#include "Settings.h"
class RSCodec {
int bits, k, nsym;
public:
RSCodec();
virtual ~RSCodec();
};
И в файле cpp
#include "RSCodec.h"
RSCodec::RSCodec() {
bits = Settings::bits;
k = Settings::k;
nsym = Settings::nsym;
printf("BITS %d, K %d, NSYM %d\n", bits, k, nsym);
}
RSCodec::~RSCodec() {}
Всегда выводит значения по умолчанию вместо обновленных.
Некоторые другие классы вместо этого работают с обновленными значениями, но доступ к ним осуществляется таким же образом (просто разные пространства имен, например Settings::RF24::, Settings::DUAL_RF24:: и т. д.).
Минимальный пример:
#include <iostream>
using namespace std;
#include "DefaultSettings.h"
#include "RSCodec.h"
int main() {
string k = "k";
string nsym = "nsym";
string val = "10";
Settings::apply_settings(k, val);
Settings::apply_settings(nsym, val);
RSCodec* rsc = new RSCodec();
return 0;
}
В моей программе k по-прежнему будет значением по умолчанию (20) вместо нового (10).
Я не думаю, что это минимально воспроизводимый пример.
Кроме того, каков текущий результат и чем он отличается от ожидаемого результата?
Я отредактировал вопрос. Кроме того, это, по сути, общая конфигурация, не заключенная в класс или структуру. Все остальные классы уже знают, где он находится в памяти (Settings.h). Идея синглтона работает, я бы просто предпочел не менять весь проект, если он тоже должен работать таким образом.
Вам действительно следует поискать «инъекцию зависимостей». `RSCodec* rsc = new RSCodec();` — бесполезное использование new. Итак: сделайте Settings локальной переменной в main (и в идеале дайте ей абстрактный базовый класс с чистыми виртуальными функциями getter/setter). Вызовите базовый класс ISettings
(потому что это интерфейс), а затем добавьте конструктор в RSCodec
, RSCodec(ISettings& setting)
, чтобы передать ваши настройки кодеку. Это внедрение зависимостей, и оно улучшит ваш код для тестирования/обслуживания/рефакторинга.
Оказывается, минимальный пример, который я привел, действительно работает. Я просто забыл вызвать apply_settings для всех моих пространств имен в программе чтения файлов.
В этом случае я бы рекомендовал закрыть из-за опечатки.
#включать использование пространства имен std;
#include "DefaultSettings.h" #include "RSCodec.h"
интервал основной() {
string k = "k";
string nsym = "nsym";
string val = "10";
Settings::apply_settings(k, val);
Settings::apply_settings(nsym, val);
RSCodec* rsc = new RSCodec();
return 0;
}
Использование глобальных переменных — не лучшая идея. Либо передайте общую конфигурацию различным модулям, либо в крайнем случае используйте шаблон Singleton.