Подтвердить что ты не робот

С++, определяющий константную переменную-член внутри конструктора класса

Обычно, когда у вас есть постоянная переменная частного члена в вашем классе, у которой есть только получатель, но нет настройки, он выглядит примерно так:

// Example.h
class Example {
    public:
        Example(const int value);
        const int getValue() const;
    private:
        const int m_value;
};


// Example.cpp
#include "Example.h"

Example::Example(const int value)
: m_value(value)
{
}

const int Example::getValue() const
{
    return m_value;
}

Теперь то, что я пытаюсь сделать, имеет постоянную переменную типа int как это, но вместо того, чтобы определять ее в секции инициализации следующим образом: : m_value(value) Мне нужно взять другой объект - я буду использовать вектор в этом примере - в качестве параметра конструктора и задайте значение m_value на основе объекта параметра. В этом случае я попытаюсь сделать векторный размер + 1, если размер выше 0. Так вот что я сделал:

Example::Example(std::vector<Example*> myVec)
{
    if (myVec.size()) {
        m_value = myVec.size() + 1;
    }
    else {
        m_value = -1;
    }
}

Но я получаю сообщение об ошибке uninitialized member 'Example::m_value' with 'const' type 'const int', и если я инициалирую m_value внутри раздела инициализации, я получаю сообщение об ошибке assignment of read-only data-member 'Example::m_value', которое имеет смысл для меня, я должен получить эти ошибки, но как я могу пойти их?

Изменить: Только способ, которым я мог редактировать m_value, находится внутри самого объекта (поскольку m_value является закрытым). Наличие только getter ограничило бы меня установкой m_value на что-либо другое, кроме того, что было установлено в конструкторе. Могу ли я извлечь выгоду из чего-либо из константы int как переменной-члена?

4b9b3361

Ответ 1

Используйте статическую функцию-член для вычисления результата, который вам нужен, и вызовите эту функцию в списке инициализации. Вот так:

// Example.h
class Example {
    public:
        Example(const int value);
        Example::Example(std::vector<Example*> myVec);

        const int getValue() const;
    private:
        const int m_value;

        static int compute_m_value(::std::vector<Example*> &myVec);
};

// Example.cpp
#include "Example.h"

Example::Example(const int value)
: m_value(value)
{
}

Example::Example(std::vector<Example*> myVec)
: m_value(compute_m_value(myVec)
{
}

const int Example::getValue() const
{
    return m_value;
}

int Example::compute_m_value(::std::vector<Example*> &myVec)
{
    if (myVec.size()) {
        return myVec.size() + 1;
    }
    else {
        return -1;
    }
}

В этом конкретном случае функция настолько проста, что вы можете просто просто использовать тернарный оператор (aka : m_value(myVec.size() > 0 ? myVec.size() + 1 : -1) в конструкторе для непосредственного вычисления значения при инициализации. Это было похоже на пример, поэтому я дал вам очень общий метод решения проблемы, даже если метод вычисления необходимого вам ответа может быть очень сложным.

Общая проблема заключается в том, что константные переменные-члены (и переменные-члены, которые являются ссылками слишком BTW) должны быть инициализированы в списке инициализаторов. Но инициализаторы могут быть выражениями, что означает, что они могут вызывать функции. Так как этот код инициализации довольно специфичен для класса, он должен быть закрытым (или, возможно, защищенным) классом. Но, поскольку он призван для создания значения перед построением класса, он не может зависеть от экземпляра класса, чтобы существовать, следовательно нет указателя this. Это означает, что это должна быть статическая функция-член.

Ответ 2

Во-первых, переменная определена в определении класса, а не в конструкторе. Он инициализирован в конструкторе.

Во-вторых, способ сделать это так же, как и ваш конструктор в настоящий момент: сохранить в нем значение из списка инициализаторов:

Example::Example(std::vector<Example*> myVec)
    : m_value(myVec.size() ? myVec.size() + 1 : -1) {
}

Ответ 3

У вас есть два основных варианта. Один из них - использовать условный оператор, который подходит для простых условий, подобных вашим:

Example::Example(const std::vector<Example*> &myVec)
  : m_value( myVec.size() ? myVec.size() + 1 : -1)
{}

Для более сложных вещей вы можете делегировать вычисление функции-члена. Будьте осторожны, чтобы не вызвать виртуальные функции-члены внутри него, так как это будет вызываться во время строительства. Это безопасно сделать static:

class Example
{
  Example(const std::vector<Example*> &myVec)
    : m_value(initialValue(myVec))
  {}

  static int initialValue(const std::vector<Example*> &myVec)
  {
    if (myVec.size()) {
      return myVec.size() + 1;
    } else {
      return -1;
    }
  }
};

Последнее, конечно, работает и с внеклассными определениями. Я поместил их в класс, чтобы сэкономить место и набрать.