Сделать список частных переменных, которые можно изменить с помощью общедоступной функции в C++

У меня есть около 20 частных логических значений в классе на С++. Я хотел бы, чтобы они были общедоступны с помощью (общедоступной) функции.

Можно ли передать имя (частной) переменной в качестве аргумента такой функции? Например,

void setTrue(std::string varName)
{
    someFunctionToConvertStringToVariable = true;
}

В качестве альтернативы я думаю, что

void setTrue(std::string varName)
{
    if (varName == "boolA")
    {
        boolA = true;
    }
    else if (varName == "boolB")
    {
        boolB = true;
    }
}

будет работать и может использовать switch(varName), чтобы уменьшить количество необходимых LOC.

Другим вариантом, по-видимому, было бы просто сделать все логические значения общедоступными, а затем получить к ним доступ с помощью myClass.boolA = true; из вызывающей программы - я не уверен, что это лучшая идея, но она определенно проще, и поэтому это аргумент в ее пользу.

Есть ли общепринятый/лучший способ сделать это? Я только что плохо поставил проблему, и есть ли более разумный способ сделать это? Возможно, enum имен переменных позволит проверять переданные переменные, но я не думаю, что это обязательно упростит установку логического значения.


person chrisb2244    schedule 29.07.2014    source источник
comment
Вместо 20 частных переменных вы можете иметь массив из 20 и передавать индекс для изменения в общедоступной функции-члене.   -  person P0W    schedule 29.07.2014
comment
Наличие 20 частных bool в одном классе - это огромный запах дизайна - это означает, что ваш класс плохо спроектирован, и способ, которым вы пытаетесь смоделировать любую проблему, которую вы решаете, должен быть переосмыслен.   -  person Yuushi    schedule 29.07.2014
comment
Вероятно, это так, но они предназначены для примерно 10 тысяч строк кода, и логические значения управляют if(boolA) cout<< "silly description of whats happening now"; способом. Длина файла журнала варьируется на несколько порядков в зависимости от того, какие логические значения установлены, поэтому, если я хочу выяснить, что не так только с одной частью, полезно установить для большинства значение false.   -  person chrisb2244    schedule 29.07.2014
comment
Тем не менее, сделать их изменяемыми из вызывающей программы более полезно для других пользователей, которые не хотят перекомпилировать библиотеку снова и снова или (что более важно) хотят изменить значение в середине программы, работающей в цикле дельты. периоды времени (т. е. программа прерывается при t=30 с, не спамить журнал в течение первых 29 с)   -  person chrisb2244    schedule 29.07.2014


Ответы (4)


Вы можете использовать std::map<std::string, bool> для хранения значений bool. Потом,

void setTrue(std::string varName)
{
    // Add some checks to make sure that varName is valid.

    varNames[varName] = true;
}
person R Sahu    schedule 29.07.2014
comment
Собираюсь попробовать это - подозреваю, что это будет ответ, который мне нужен, хотя - person chrisb2244; 29.07.2014
comment
Проверка правильности varname заключается в проверке возвращаемого значения map::find (key) вместо использования произвольного доступа... если оно равно map::end, оно недействительно. - person Theolodis; 29.07.2014
comment
Правильный ответ, но, пожалуйста, измените std::string на константную ссылку, а также используйте find. - person Keith; 29.07.2014
comment
Как указывали и другие, здесь не следует использовать std::map::operator [], поскольку, если varName отсутствует, он добавит его в varNames, и это не главное, используйте std::map::find - person P0W; 29.07.2014
comment
Это, безусловно, ответ, который я просил, поэтому отметил, что он принят. Возможно, изучив это, мой вопрос не был отчаянно правильно поставлен, но это дает мне что-то, над чем можно подумать/поработать. Спасибо - person chrisb2244; 29.07.2014
comment
Обратите внимание, что вы можете использовать карту bool*, если хотите сохранить исходный список членов для удобства внутри класса. - person Keith; 29.07.2014
comment
@ chrisb2244 возражения заключаются в том, что вы можете создавать новые записи карты, передавая строки, которых вы не ожидали; и если вы не хотите такого поведения, решение состоит в том, чтобы создать все именованные записи карты в вашем конструкторе и использовать map::find вместо map::operator[]. - person M.M; 29.07.2014
comment
@Keith - Спасибо, это полезно - я пытался найти указатели в нужном месте, чтобы сделать это, но теперь с вашим советом это было просто. @MattMcNabb - Также спасибо, поместите это в мою функцию. Теперь это выглядит довольно запутанно, но, по крайней мере, реализация инкапсулирована вдали от пользователя — *(object.myMap["myName"]) = true/false; и так далее. Успею ...myMap.find("myName") - person chrisb2244; 29.07.2014

Если список этих переменных не изменится, я могу предложить вам использовать перечисление и переопределить оператор нижнего индекса:

enum MyBools
{
    First = 0,      
    BoolA = First,       
    BoolB,       
    //...
    Bool20,     
    Last = Bool20,
}    

class MyIndexedBools
{
private:
    bool m_Bools[MyBools::Last + 1];

public:
    bool& operator[] (MyBools index);
};

bool& operator[] (MyBools index);
{
    if (index < First || index > Last)
         throw "error";

    return m_Bools[index];
}

Он не расширяется во время выполнения, но обеспечивает лучшую безопасность во время компиляции, чем карты.

person Eugene Podskal    schedule 29.07.2014
comment
Перечисление - это действительно один из способов. В С++ 11 вы можете указать, что перечисление должно иметь size_t в качестве резервного хранилища, чтобы при преобразовании в индекс не требовалось преобразование... а также потому, что с беззнаковым хранилищем First становится ненужным. Следующим шагом будет использование std::array. - person Matthieu M.; 29.07.2014

Ваше второе решение - это путь сюда, однако я думаю, что случай переключения не уменьшает LOC, помимо того факта, что это не будет работать с `std::string!

void setTrue(const std::string& varName)
{
    if (varName == "boolA")
    {
        boolA = true;
    }
    else if (varName == "boolB")
    {
        boolB = true;
    }
}

VS:

void setTrue(const std::string& varName)
{
    switch(str2int (varName))
    {
    case str2int ("boolA"):
        boolA = true;
        break;
    case str2int("boolB"):
        boolB = true;
        break;
    default: 
        assert (false);
    }
}

И имейте в виду, что если вы не хотите изменять переданный параметр, рекомендуется передать его как const! В этом случае я бы лично передал его как const ссылка.

person Theolodis    schedule 29.07.2014
comment
Вы пропустили копирование str2int реализации по ссылке выше - person P0W; 29.07.2014
comment
Я здесь не для того, чтобы дублировать код, я просто хотел дать представление о LOC .... Я сделал ссылку на исходный вопрос, так что не стесняйтесь брать его оттуда;) - person Theolodis; 29.07.2014

Двадцать bool действительно много.

Вместо этого я бы посоветовал использовать bitset, проиндексированный с помощью констант (например, используя enum) . Предполагая С++ 11:

class SomeClass {
public:
    enum class Flag: size_t {
        Flag1,
        Flag2,
        Flag3,
        ...,
        Flag20
    };

    bool get_flag(Flag f) const { return _flags.test(size_t(f)); }

    void set_flag(Flag f, bool value) { _flags.set(size_t(f), value); }

private:
    std::bitset<size_t(Flag20) + 1> _flags;
}; // class SomeClass

Примечание: все обращения за пределы диапазона выполняются bitset, удобно, не так ли?

person Matthieu M.    schedule 29.07.2014