Квалификаторы C++ и спецификаторы классов хранения

C++ Программирование и разработка

C++

CV расшифровывается как Constant-Volatile. Объявление объекта, которому не предшествуют const и / илиvolatile — это неквалифицированный тип cv. С другой стороны, объявление объекта, которому предшествуют const и / или volatile, является типом с квалификацией cv. Если объект объявлен как const, значение в его местоположении нельзя изменить. Неустойчивая переменная — это переменная, значение которой находится под влиянием программиста и, следовательно, не может быть изменено компилятором. Спецификаторы класса хранения относятся к жизни, месту и способу существования типа. Спецификаторы класса хранилища — статические, изменяемые, thread_local и extern.

В этой статье объясняются квалификаторы C ++ и спецификаторы классов хранения. Таким образом, некоторые предварительные знания C ++ пригодятся, чтобы по-настоящему оценить статью.

Отборочные

const

Объект, объявленный константой, — это объект, хранилище (местоположение) которого не может быть изменено. Например, в заявлении:

int const theInt = 5;

Значение 5 в хранилище для theInt не может быть изменено.

volatile

Рассмотрим следующее утверждение:

int portVal = 26904873;

Иногда компиляторы вмешиваются в значение переменной в надежде оптимизировать программу. Компилятор может поддерживать значение переменной как постоянное, если оно не должно быть постоянным. Компилятор может вмешиваться в значения объектов, которые связаны с отображенными в память портами ввода-вывода или процедурами обслуживания прерываний периферийных устройств. Чтобы предотвратить такое вмешательство, сделайте переменную изменчивой, например:

int volatile portVal;

portVal = 26904873;

or like:

int volatile portVal = 26904873;

Сочетание const и volatile:

const и volatile могут встречаться в одном операторе следующим образом:

int const volatile portVal = 26904873;

cv-квалификаторы

Переменная, которой предшествуют const и / или volatile, является типом с квалификацией cv. Переменная, перед которой не указаны ни const, ни volatile, ни оба, являются неквалифицированным типом cv.

Ordering:

Один тип может быть более квалифицированным, чем другой:

  • Ни один cv-квалификатор не меньше квалификатора const
  • Ни один cv-квалификатор не может быть меньше квалификатора volatile.
  • Ни один cv-квалификатор не меньше квалификатора const-volatile
  • Квалификатор const меньше, чем const-летучий квалификатор
  • Квалификатор volatile меньше квалификатора const-volatile

Пока еще не сделан вывод о том, что const и volatile имеют одинаковый ранг.

Массив и созданный объект:

Когда массив объявлен константой, как в следующем заявлении, это означает, что значение каждого элемента массива не может быть изменено:

const char arr[] = {‘a’, ‘b’, ‘c’, ‘d’};

Будь то «a», «b», «c» или «d», его все равно нельзя изменить на какое-либо другое значение (символ).

Аналогичная ситуация применяется к экземпляру объекта класса. Рассмотрим следующую программу:

#include <iostream>
using namespace std;

class Cla
{
public:
char ch0 = ‘a’;
char ch1 = ‘b’;
char ch2 = ‘c’;
char ch3 = ‘d’;
};

int main()
{
const Cla obj;

return 0;
}

Из-за утверждения «const Cla obj;» с const в функции main () ни ’a’, ни ’b’, ни ’c’, ни ’d’ не могут быть изменены на какое-либо другое значение.

Спецификаторы класса хранения

Спецификаторы класса хранения статические, изменяемые, thread_local, и внеш.

Спецификатор статического класса хранения

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

Следующая программа иллюстрирует это с помощью рекурсивной функции:

#include <iostream>
using namespace std;

int funct()
{
static int stac = 10;
cout << stac < 50)
{
cout << \n;
return 0;
}
funct();
}

int main()
{
funct();

return 0;
}

Результат:

10 20 30 40 50

Если статическая переменная не инициализируется при ее первом объявлении, она принимает значение по умолчанию для ее типа.

Статический спецификатор также можно использовать с членами класса; использование здесь другое. Здесь он позволяет получить доступ без создания экземпляра объекта.

Следующая программа иллюстрирует это для элемента данных:

#include <iostream>
using namespace std;

class Cla
{
public:
static const int num = 8;
};

int main()
{
cout << Cla::num << \n;

return 0;
}

Результат:

8

Статический член данных должен быть постоянным. Обратите внимание, что использование оператора разрешения области видимости для доступа к статической переменной вне ее области видимости (в основной функции).

Следующая программа иллюстрирует использование «статики» для функции:

#include <iostream>
using namespace std;

class Cla
{
public:
static void method ()
{
cout << «Of static member function!» << \n;
}
};

int main()
{
Cla::method();

return 0;
}

Обратите внимание, что использование оператора разрешения области видимости для доступа к статической функции вне ее области (в основной функции).

Изменяемый спецификатор

Помните, что из вышесказанного, если экземпляр объекта начинается с const, значение любого из его обычных элементов данных не может быть изменено. И для изменения любого такого  данных он должен быть объявлен изменяемым.

Следующая программа иллюстрирует это:

#include <iostream>
using namespace std;

class Cla
{
public:
char ch0 = ‘a’;
char ch1 = ‘b’;
mutable char ch2 = ‘c’;
char ch3 = ‘d’;
};

int main()
{
const Cla obj;
obj.ch2 = ‘z’;
cout << obj.ch0 << ‘ ‘ << obj.ch1 << ‘ ‘ << obj.ch2 << ‘ ‘ << obj.ch3 << ‘ ‘ << \n;

return 0;
}

Результат:

‘a’ ‘b’ ‘z’ ‘d’

Спецификатор thread_local

При нормальном выполнении программы выполняется один сегмент кода, затем следующий сегмент кода, за ним следует другой сегмент кода и так далее. Это одна нить; основной поток. Если два сегмента кода выполняются одновременно (одинаковой продолжительности), то требуется второй поток. Результат второго потока может быть даже готов раньше основного потока.

Функция main () похожа на основной поток. Программа может иметь более двух потоков для такого асинхронного поведения.

Второй поток нуждается в области (области блока) для работы. Обычно это обеспечивается областью действия функции, функцией. Переменная во внешней области видимости, которую можно увидеть в области видимости второго потока.

Следующая короткая программа иллюстрирует использование спецификатора thread_local:

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

thread_local int inter = 1;

void thread_function()
{
inter = inter + 1;
cout << inter << «nd thread\n«;
}

int main()
{
thread thr(&thread_function);   // thr starts running
cout << inter << «st or main thread\n«;
thr.join();   // main thread waits for the thread, thr to finish
return 0;
}

Результат:

1st or main thread

2nd thread

Переменная inter, которой предшествует thread_local, означает, что inter имеет отдельный экземпляр в каждом потоке. И что он может быть изменен в разных потоках, чтобы иметь разные значения. В этой программе ему присваивается значение 1 в основном потоке и изменяется на значение 2 во втором потоке.

Для работы потоку нужен специальный объект. Для этой программы библиотека, включенная в «#include

», имеет класс, называемый потоком, из которого был создан объект thr. Конструктор этого объекта принимает в качестве аргумента ссылку на функцию потока. Имя функции потока в этой программе:thread_function ().

Функция join () для специального объекта в его занятой позиции заставляет основной поток ждать завершения выполнения второго потока, прежде чем он продолжит выполнение, в противном случае функция main () может завершиться без (второго) потока, имеющего дала свой результат.

Спецификатор extern

Проще говоря, для объявления память не выделяется для переменной или функции, а для определения выделяется память. Зарезервированное слово extern позволяет объявить глобальную переменную или функцию в одном файле, но определить в другом. Такие файлы называются единицами перевода для всего приложения C ++.

Введите следующую программу и сохраните ее с именем файла mainFile:

#include <iostream>
using namespace std;

int myInt;

const char ch;

void myFn();

int main()
{
myFn();

return 0;
}

Переменная myInt, постоянная переменная ch и функция myFn () были объявлены без определения.

Введите следующую программу с определениями и сохраните ее с именем файла otherFile в том же каталоге:

#include <iostream>
using namespace std;

int myInt = 10;

const char ch = ‘c’;

void myFn()
{
cout << «myFn() says « << myInt << » and « << ch <<\n;
}

Попробуйте скомпилировать приложение в терминале (командная строка DOS) с помощью следующей команды и обратите внимание, что оно может не компилироваться:

g++ mainfile.cpp otherFile.cpp o complete.exe

Теперь перед тремя объявлениями в mainFile поставьте слово «extern», как показано ниже:

extern int myInt;

extern const char ch;

extern void myFn();

Повторно сохраните файл mainFile. Скомпилируйте приложение с помощью:

g++ mainfile.cpp otherFile.cpp o complete.exe

(Вот как отдельные файлы для одного и того же приложения компилируются на C ++)

И он должен компилироваться. Теперь запустите приложение complete.exe, и результат должен быть:

myFn() says 10 and c

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

Когда использовать extern? Используйте его, когда у вас нет файлов заголовков с глобальными объявлениями.

«Extern» также используется с объявлениями шаблонов — см. Ниже.

Заключение

Переменная, которой предшествуют const и / или volatile, является типом с квалификацией cv. Переменная, которой не предшествуют ни const, ни volatile, ни то и другое, является неквалифицированным типом cv.

Спецификаторы класса хранения статические, изменяемые, thread_local, и внеш. Они влияют на продолжительность жизни (продолжительность), место и способ использования переменных в приложении.

Читайте также:  Массив указателей C++
Оцените статью
bestprogrammer.ru
Добавить комментарий