Статические переменные и методы класса

217
10 октября 2017, 04:41

Как в современном (c++11 и более позднем) объявлять статические переменные в классе и можно ли вообще это делать?

#include <iostream>
#include <string>
using namespace std;
int main()
{
    class Class
    {
        static const short unsigned id = 1;
        static const string name = "Заголовок 1";
        public:
        static short unsigned getId()
        {
            return id;
        }
        static string getName()
        {
            return name;
        }
    };
    cout<<Class::getId()<<' '<<Class::getName()<<endl;
    return 0;
}

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

g++ -Wall -march=native -msse3 -O3 -fomit-frame-pointer -pipe -o "oop" "oop.cpp" (в каталоге: /home/ilya/Downloads/Qt)
oop.cpp: В функции «int main()»:
oop.cpp:10:36: ошибка: локальный класс «class main()::Class» не должен иметь статический элемент данных «const short unsigned int main()::Class::id» [-fpermissive]
   static const short unsigned id = 1;
                                    ^
oop.cpp:11:30: ошибка: локальный класс «class main()::Class» не должен иметь статический элемент данных «const string main()::Class::name» [-fpermissive]
   static const string name = "Заголовок 1";
                              ^~~~~~~~~~~~~~~~~~~~~~
oop.cpp:11:23: ошибка: инициализация внутри класса статического элемента данных «const string main()::Class::name» нелитерального типа
   static const string name = "Заголовок 1";
                       ^~~~
oop.cpp:11:30: ошибка: вызов non-constexpr функции «std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [с _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]»
   static const string name = "Заголовок 1";
                              ^~~~~~~~~~~~~~~~~~~~~~
Сборка завершилась с ошибкой.

И если определять из вне.

#include <iostream>
#include <string>
using namespace std;
int main()
{
    class Class
    {
        public:
        static short unsigned id;
        static string name;
    };
    Class::id = 1;
    Class::name = "Заголовок 1";
    cout<<Class::id<<' '<<Class::name<<endl;
    return 0;
}

То всё равно не получается.

g++ -Wall -march=native -msse3 -O3 -fomit-frame-pointer -pipe -o "oop" "oop.cpp" (в каталоге: /home/ilya/Downloads/Qt)
oop.cpp: В функции «int main()»:
oop.cpp:11:25: ошибка: локальный класс «class main()::Class» не должен иметь статический элемент данных «short unsigned int main()::Class::id» [-fpermissive]
   static short unsigned id;
                         ^~
oop.cpp:12:17: ошибка: локальный класс «class main()::Class» не должен иметь статический элемент данных «std::__cxx11::string main()::Class::name» [-fpermissive]
   static string name;
                 ^~~~
Сборка завершилась с ошибкой.

Почему так происходит и что я делаю не так?

Answer 1

Обратите внимание на ошибку. Там упоминается, что класс локальный. Вот так все нормально работает.

#include <iostream>
#include <string>
using namespace std;

class Class
{
public:
    static const int id;
    static const string name;
};
const int Class::id{111};
const string Class::name = "rectangle";
int main()
{
cout<<Class::id<<' '<<Class::name<<endl;
return 0;
}

Можно убрать константность, инициализация от этого не пострадает

#include <iostream>
#include <string>
using namespace std;

class Class
{
public:
    static int id;
    static string name;
};
int Class::id{111};
string Class::name = "rectangle";
int main()
{
Class c;
cout<<c.id<<' '<<c.name<<endl;
return 0;
}

Во втором примере можно обращаться по иени класса и далее через ::, я просто привел для примера через экземпляр и . Также рекомендую обратить внимание на фигурную инициализацию, через {}, как сделал для id, она имеет ряд преимуществ, но иногда стоит быть осторожнее, потому что из нее получается объект std::initializer_list.

Answer 2

Этот ответ относится к принципам инициализации.

Для инициализации Вам нужно узнать, где находится переменная в памяти. При объявлении класса, такой информации не будет, Вам нужно определение. Поэтому, мы указываем определение, типа int Class::id, тем самым показывая, где будет создана переменная, и далее инициализируем ее.

С константами ситуация другая. Вы не сможете взять адрес у константы. Если захотите, Вам придется написать что-то вроде const int Class::id. Константы работают во время компиляции и заменяются на свои значения.

При этом должно существовать только одно определение статического члена, поэтому его надо отправить в .срр файл, или где там определены функции-члены.

READ ALSO
Логика в майнере nheqminer

Логика в майнере nheqminer

Есть задание, написать свой майнер, за основу взяли https://githubcom/nicehash/nheqminer, для тестов выбрал nanopool, использую библиотеку "boost"

229
Ошибка &ldquo;Файл не найден&rdquo; Qt Creator

Ошибка “Файл не найден” Qt Creator

Написал несложную программу на с++ в Qt CreatorПрограмма работала

198
Помогите разобраться с регулярков в JS

Помогите разобраться с регулярков в JS

В общем у меня есть регулярк она должна очистить все и выдать числа

201
Зацикливается анимация ожидания

Зацикливается анимация ожидания

Здравствуйте! На сайте после нажатия на кнопку происходят определенные действия, с помощью ajax запросаПока ждем ответ от сервера показывается...

180