LINUX.ORG.RU

Инициализация const переменной класса?

 


0

2

Приветствую.

Как бы вот такое провернуть, чтобы можно было объявить переменную как const даже для методов класса с учетом того, что в конструкторе нужно сначала проинициализировать другие переменные, прежде чем посчитать const ?

Т.е. что то вроде


class X
{
private:
  T * ptr;
public:
  const std::string city;
  X ()
  {
     ...
     ptr->start();
     city = ptr->CalcCity();
  }
}
★★★

Ответ на: комментарий от wolverin

Если в современном C++ есть способ проинициализировать несколько полей одним вызовом функции (через structural binding???), тогда получится сохранить T*. В противном случае его придётся создавать заново.

annulen ★★★★★
()
Ответ на: комментарий от annulen

объявил

    const string CalcCity(void) const
    {
        string city("бла");
        return city;
   
    }

в конструкторе попытался city = CalcCity();, все та же ошибка

: error: passing ‘const string’ {aka ‘const std::__cxx11::basic_string<char>’} as ‘this’ argument discards qualifiers [-fpermissive]
  city = CalcCity();
                  ^
In file included from /usr/include/c++/8/string:52,
                 from /usr/include/c++/8/stdexcept:39,
                 from /usr/include/c++/8/array:39,
                 from /usr/include/c++/8/tuple:39,
                 from /usr/include/c++/8/bits/unique_ptr.h:37,
                 from /usr/include/c++/8/memory:80,
                 from /usr/include/c++/8/thread:39,
                 from Downloader.cpp:6:
/usr/include/c++/8/bits/basic_string.h:664:7: note:   in call to ‘std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator=(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
       operator=(const basic_string& __str)

вообще T* в базовом классе инициализируется, но потомки по разному используют, т.е. попробовать в инициализацию переместить место тела конструктора…

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

да так прокатывает… на ламбду заменить тогда!? правда выглядит странно, что часть кода конструктора теперь в инициализации переменной

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Конечно такое не скомпилируется — это же присваивание написано, а не инициализация. Присваивать значение константе (без костылей) запрещено. Инициализация вот так выглядит:

public:
  const std::string city { CalcCity(); }

или

X::X() : city(CalcCity()) { ... }
annulen ★★★★★
()
Ответ на: комментарий от annulen

да спасибо, так уже проверил, но так чего то не хочет

X::X() :
          city([this](){
                    string cty = "undefined";
                    ...
                    return cty;
                })

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от annulen

не там какая то другая ошибка

error: no matching function for call to ‘std::__cxx11::basic_string<char>::basic_string(X::X()::<lambda()>)’
wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 2)
Ответ на: комментарий от annulen

Если в современном C++ есть способ проинициализировать несколько полей одним вызовом функции (через structural binding???), тогда получится сохранить T*. В противном случае его придётся создавать заново.

Вот здесь наврал: порядок инициализации в С++ строго определён и можно на него заложиться. Не только базовые классы инициализируются раньше, но и всё поля, объявленные выше в декларации класса.

annulen ★★★★★
()
Ответ на: комментарий от annulen

если порядок определен, то указатель получается уже должен быть нормальным, тем более он в конструкторе базового класса у меня создается, а в потомке я уже просто «донастройки» его делаю, которые получаются теперь в инициализации const переменной, а не в теле конструктора - вот что выглядит странно на мой ламерский взгляд.

wolverin ★★★
() автор топика
Ответ на: комментарий от Bfgeshka

ну вообщем то задача так интереса ради можно ли проинициализировать хоть как конст, до инициализации которой уже другие переменные класса используются.

wolverin ★★★
() автор топика
Ответ на: комментарий от wolverin

Если переместить эти донастройки в метод std::string T::calcCity() и дёргать ptr->calcCity() в инициализаторе, то может быть даже что-то логичное получится

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)

city = ptr->CalcCity();

вот это уже значит что она не const

Сделай инициализацию в конструкторе, а потом вызывай ее из геттера.

class X
{
private:
  T * ptr;
  std::string city;

public:
  std::string GetCity()
  {
    return city;
  }

  X ()
  {
     ...
     ptr->start();
     city = ptr->CalcCity();
  }
}
aiqu6Ait ★★★★
()
Ответ на: комментарий от wolverin

Тут такой момент, что теперь нужно покрыть все конструкторы этой инициализацией, потому что константа не инициализирована при определении.

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

Bfgeshka ★★★★★
()
Последнее исправление: Bfgeshka (всего исправлений: 1)
Ответ на: комментарий от Bfgeshka

по большому счету непонятно мне другое - почему в инициализации переменной можно написать кучу кода, а просто в теле конструктора это сделать нельзя - где логика!?

wolverin ★★★
() автор топика

Если тебе нужно свойство объекта, которое вычисляется при его создании и затем не меняется — ну, и опиши его как класс с конструктором, private членом и геттером без сеттера. Что за манера насиловать стандарт языка, впихивая невпихуемое?

alegz ★★★★
()
Последнее исправление: alegz (всего исправлений: 1)