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

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

В C++ статические переменные-члены нельзя инициализировать внутри класса. Внутри класса находится только объявление; определение должно быть вне тела определения класса, обычно инициализируется в файле реализации класса, например:double Account::Rate = 2.25;

Ключевое слово static можно использовать только в объявлении внутри тела определения класса; при определении его нельзя помечать как static.

В C++ константные переменные-члены также нельзя инициализировать при определении класса; их можно инициализировать только через список инициализации конструктора, и при этом конструктор должен существовать.

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

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

class Test{ public: Test():a(0){} enum {size1=100,size2=200}; private: const int a;//Можно инициализировать только в списке инициализации конструктора static int b;//Определить и инициализировать в файле реализации класса conststatic int c;//То же, что и static const int c; }; int Test::b=0;//статические переменные-члены нельзя инициализировать в списке инициализации конструктора, потому что они не принадлежат конкретному объекту. cosnt intTest::c=0;//Примечание: при присваивании значения статической переменной-члену модификатор static не нужен, но нужно добавить const.

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

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

  • 1. Не могут напрямую обращаться к нестатическим переменным-членам класса или вызывать нестатические функции-члены.
  • 2. Не могут быть объявлены как virtual.

Об инициализации членов static, const, static const и const static

1. Инициализация членов const в классе:

При создании const в классе нельзя задать ему начальное значение.

class foo{ public: foo():i(100){} private: const int i=100;//ошибка!!! }; //Или инициализируйте его таким образом foo::foo():i(100){}

2. Инициализация статических членов в классе:

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

data type class name::static data member name = value;
class foo{ public: foo(); private: staticint i; }; intfoo::i=20;

Это означает:

  • 1. Инициализация выполняется вне тела класса, и static не добавляется впереди, чтобы избежать путаницы с обычными статическими переменными или объектами.
  • 2. При инициализации не добавляйте спецификаторы доступа члена, такие как private, public, и т. д.
3. При инициализации используйте оператор разрешения области видимости, чтобы указать класс, к которому она принадлежит. Следовательно, статические элементы данных являются членами класса, а не членами объекта.

3. Инициализация членов static const и const static в классе

Эти два способа записи дают одинаковый эффект. Для простоты запоминания здесь объясняется только один общий способ инициализации:

class Test{ public: static const int mask1; conststatic int mask2; }; constTest::mask1=0xffff; constTest::mask2=0xffff; //Их инициализация ничем не отличается, хотя один — статическая константа, а другой — константный статический. Статические хранятся в области глобальных переменных; фактически конечный результат одинаков. Разные компиляторы могут обрабатывать их по-разному, но конечный результат одинаков.

Полный пример

Пример

#ifdef A_H_ #define A_H_ #include <iostream> usingnamespace std; class A{ public: A(int a); staticvoid print();//Статическая функция-член private: static int aa;//Объявление статического элемента данных staticconst int count;//Константный статический элемент данных (может быть инициализирован в конструкторе) const int bb;//Константный элемент данных }; int A::aa=0;//Определение + инициализация статического элемента const int A::count=25;//Определение + инициализация статического константного элемента A::A(int a):bb(a){//Инициализация константного элемента aa+=1; } void A::print(){ cout<<"count="<<count<<endl; cout<<"aa="<<aa<<endl; } #endif void main(){ A a(10); A::print();//Доступ к статической функции-члену через класс a.print();//Доступ к статической функции-члену через объект }

Место инициализации

Статические элементы не могут быть инициализированы в определении класса (кроме int). Они не могут быть инициализированы в заголовочном файле.

Например, если определён myclass.h, он обычно инициализируется в myclass.cpp.


Статические члены классов C++ (static)

Статические члены предлагаются для решения проблемы совместного использования данных. Существует много способов обеспечить совместное использование, например, один из методов — задание глобальных переменных или объектов. Однако глобальные переменные или объекты имеют ограничения. В этой главе мы в основном рассматриваем использование статических членов класса для совместного использования данных.

Статический член данных

В классе статические члены позволяют обеспечить совместное использование данных между несколькими объектами, а использование статических членов данных не нарушает принцип сокрытия, тем самым обеспечивая безопасность. Следовательно, статические члены — это члены, совместно используемые всеми объектами класса, а не члены конкретного объекта.

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

Правила использования и меры предосторожности для статических членов данных приведены ниже:

1. При определении или объявлении статического члена данных добавьте ключевое слово static в начале.

2. Инициализация статических членов отличается от инициализации обычных членов данных. Формат инициализации статических членов данных следующий:

 
<data type><class name>::<static data member name>=<value>

Это означает:

  • (1) Инициализация выполняется вне тела класса, и static не добавляется в начале, чтобы избежать путаницы с обычными статическими переменными или объектами.
  • (2) При инициализации не добавляйте спецификаторы управления доступом члена, такие как private, public и т. д.
  • (3) При инициализации используйте оператор разрешения области видимости, чтобы указать класс, которому он принадлежит. Следовательно, статические члены данных являются членами класса, а не членами объекта.

3. Статические элементы данных хранятся статически; они имеют статическое время жизни и должны быть инициализированы.

4. При обращении к статическому элементу данных используйте следующий формат:

<class name>::<static member name>

Если разрешение доступа статического элемента данных позволяет (т. е. он является открытым членом), к статическому элементу данных можно обращаться в программе, используя приведённый выше формат.

Ниже приведён пример, иллюстрирующий применение статических элементов данных:

Пример

#include … class Myclass{ public: Myclass(int a, int b, int c); void GetNumber(); void GetSum(); private: int A, B, C; static int Sum; }; int Myclass::Sum = 0; Myclass::Myclass(int a, int b, int c){ A = a; B = b; C = c; Sum += A+B+C; } void Myclass::GetNumber(){ cout<<"Number="<<a<<","<<b<<","<<c<<endl; } void Myclass::GetSum(){ cout<<"Sum="<<sum<<endl; } void main(){ Myclass M(3, 7, 10),N(14, 9, 11); M.GetNumber(); N.GetNumber(); M.GetSum(); N.GetSum(); }

Из вывода видно, что значение Sum одинаково для объекта M и объекта N. Это потому, что при инициализации объекта M значения трёх int-членов данных объекта M суммируются и присваиваются Sum, поэтому Sum хранит это значение. При инициализации объекта N значения трёх int-членов данных объекта N суммируются и затем прибавляются к существующему значению Sum, поэтому Sum будет хранить новое значение. Следовательно, значение, на которое ссылаются через объект M или объект N, одно и то же, а именно 54.

Статическая функция-член

Как и статические данные-члены, статические функции-члены являются статическими членами класса; они не являются членами объекта. Поэтому для обращения к статическим членам не требуется использовать имя объекта.

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

Пример

#include … class M{ public: M(int a){ A=a; B+=a; } static void f1(M m); private: int A; static int B; }; void M::f1(M m) { cout<<"A="<<m.a<<endl; cout<<"B="<<b<<endl; } int M::B=0; void main() { M P(5),Q(10); M::f1(P); //При вызове не нужно указывать имя объекта M::f1(Q); }

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

  
<class name>::<static member function name>(<parameter list>);

Способы инициализации различных типов переменных-членов в C++

Различные типы членов в C++ имеют разные способы инициализации в зависимости от того, являются ли они статическими или const. Синтаксис Java не настолько сложен; неудивительно, что так много людей идут изучать Java. Раньше меня спрашивали об этом на собеседовании, и я не мог ответить. При написании кода я часто всё путал. Здесь я просмотрел книгу и обобщил это.

//-----------------Test.h---------------------------- #pragma once class Test { private : int var1; // int var11= 4; неверный способ инициализации const int var2 ; // const int var22 =22222; неверный способ инициализации static int var3; // static int var3333=33333; ошибка: только статические const int-члены можно инициализировать прямым присваиванием static const int var4=4444; // Верно, статические const-члены можно инициализировать напрямую static const int var44; public: Test(void); ~Test(void); }; //--------------------Test.cpp----------------------------------- #include ".\test.h" int Test::var3 = 3333333; // Правильный способ инициализации статических членов // int Test::var1 = 11111;; ошибка: только статические члены могут быть инициализированы // int Test::var2 = 22222; ошибка // int Test::var44 = 44444; // неправильный способ, даёт ошибку переопределения Test::Test(void):var1(11111),var2(22222)Правильный способ инициализации//var3(33333) нельзя инициализировать здесь { var1 =11111; // Правильно, обычные переменные также можно инициализировать здесь //var2 = 222222; ошибка, потому что константе нельзя присвоить значение; её можно инициализировать только в "инициализаторе конструктора (списке инициализации конструктора)" var3 =44444; // Это присваивание корректно, но поскольку все объекты совместно используют один статический член, оно повлияет на другие; это вряд ли можно назвать инициализацией } Test::~Test(void){} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Некоторые переменные-члены имеют специальные типы данных, и способы их инициализации также отличаются от переменных-членов обычных типов данных. К таким специальным типам переменных-членов относятся:

  • a. Константные переменные-члены
  • b. Ссылочные переменные-члены
  • c. Статические переменные-члены
  • d. Целочисленные статические константные переменные-члены
  • e. Нецелочисленные статические константные переменные-члены

Для константных переменных-членов и ссылочных переменных-членов инициализация должна выполняться через список инициализации конструктора. Присваивание значений константным переменным-членам и ссылочным переменным-членам внутри тела конструктора не представляется возможным.

Инициализация статических переменных-членов также довольно специфична.

См. следующий код и комментарии к нему:

// Инициализация специального элемента данных #include <iostream> using namespace std; class BClass { public: BClass() : i(1),ci(2), ri(i) // Для константных переменных-членов и ссылочных переменных-членов инициализация должна выполняться через параметризованный список. Присваивание значений внутри тела конструктора не представляется возможным. { // Обычная переменная-член } voidprint_values() { cout<< "i =\t" << i << endl; cout<< "ci =\t" << ci << endl; cout<< "ri =\t" << ri << endl; cout<< "si =\t" << si << endl; cout<< "csi =\t" << csi << endl; cout<< "csi2 =\t" << csi2 << endl; cout<< "csd =\t" << csd << endl; } private: inti; // Константная переменная-член constint ci; // Ссылочная переменная-член int&ri; // Статическая переменная-член staticint si; //staticint si2 = 100; // ошибка: только статические константные переменные-члены можно инициализировать таким образом // Статическая константная переменная-член staticconst int csi; // Инициализация статической константной переменной-члена (целочисленный тип) (1) staticconst int csi2 = 100; // Статическая константная переменная-член (нецелочисленный тип) staticconst double csd; //staticconst double csd2 = 99.9; // ошибка: только статические константные целочисленные элементы данных могут быть инициализированы внутри класса // Инициализация статической переменной-члена (целочисленный тип) }; // Инициализация статической константной переменной-члена (целочисленный тип) int BClass::si = 0; // Инициализация статической константной переменной-члена (нецелочисленный тип) const int BClass::csi = 1; // При инициализации csi2 в (1), согласно Stanley B. Lippman, следующая строка необходима. const double BClass::csd = 99.9; // Однако в VC2003 наличие следующей строки вызовет ошибку, тогда как в VC2005 следующая строка необязательна; это зависит от компилятора. C++ сводка по статическим членам, C++, static const int BClass::csi2; int main(void) { BClassb_class; b_class.print_values(); return0; }

C++ сводка по статическим членам, C++, static

Впоследствии я глубоко обдумал это и решил тщательно обобщить ключевые моменты о статических членах класса, чтобы в будущих собеседованиях не быть пассивным в таких вопросах.

Статические члены класса включают две части: статические члены данных и статические функции-члены.

Статические члены данных

Статический член данных

1. Определение статических элементов данных.

Статические элементы данных на самом деле являются глобальными переменными в области видимости класса. Поэтому определение (инициализацию) статических элементов данных не следует размещать в заголовочных файлах. (Объявление vs. определение (инициализация)) Способ их определения такой же, как у глобальных переменных. Пример:

Файл

xxx.h// Объявление. Стандартный C++ поддерживает инициализацию целочисленных типов в теле класса, но VC6 — нет.class base{ private: static const int _i;File }; xxx.cpp// Определение (инициализация) не ограничено ограничениями доступа private и protected.const int base::_i=10;Примечание:

Не пытайтесь определять (инициализировать) статические элементы данных в заголовочных файлах. В большинстве случаев это вызовет ошибки, такие как повторное определение. Даже если добавитьили#ifndef #define #endifэто всё равно не сработает.#pragma once2. Статические элементы данных являются общими для всех объектов класса, включая объекты производных классов этого класса. То есть объекты производного класса и объекты базового класса совместно используют статические элементы данных базового класса. Пример:

// Объявление

class base{ public : static int _num;// Реальное определение статического элемента данных }; int base::_num=0;// Результат — 1,2; видно, что производный класс и базовый класс совместно используют один статический элемент данных. class derived:public base{ }; main() { base a; derived b; a._num++; cout<<"статический элемент данных number_num базового класса равен"<<a._num<<endl; b._num++; cout<<"статический элемент данных производного класса _num равен"<<b._num<<endl; } 3. Статические элементы данных могут использоваться как аргументы по умолчанию функций-членов, тогда как обычные элементы данных — нет. Пример:

// Верно, _staticVar — статический элемент данных

class base{ public : static int _staticVar; int _var; void foo1(int i=_staticVar);// Ошибка, _var — обычный элемент данных void foo2(int i=_var);4. Тип статического элемента данных может быть типом его собственного класса, тогда как обычный элемент данных — нет. Обычный элемент данных может быть объявлен только как указатель или ссылка на тип его собственного класса. Пример: };

// Верно, статический элемент данных

class base{ public : static base_object1;// Ошибка base _object2;// Верно, указатель base *pObject;// Верно, ссылка base &mObject;5. Я не знаю, относится ли эта возможность к стандартному C++ или является особенностью, специфичной для VC6. };

Значение статического элемента данных можно законно изменить в константной функции-члене. Пример:

// функция-член const

class base{ public: base(){ _i=0; _val=0; } mutable int _i; static int _staticVal; int _val; void test() const{// Верно, изменяемый элемент данных _i++;// Верно, статический элемент данных _staticVal++;// Ошибка _val++;Статические функции-члены } }; int base::_staticVal=0;

Статическая функция-член

1. Адрес статической функции-члена можно сохранить в обычном указателе на функцию, тогда как адрес обычной функции-члена нужно сохранять в указателе на функцию-член класса. Пример:

// Обычный указатель на функцию

class base{ static int func1(); int func2(); }; int (*pf1)()=&base::func1;// Указатель на функцию-член int (base::*pf2)()=&base::func2;2. Статические функции-члены не могут вызывать нестатические члены класса, потому что статические функции-члены не содержат указателя this.

3. Статические функции-члены не могут быть одновременно объявлены как virtual, const или volatile. Пример:

// Ошибка

class base{ virtual static void func1();// Ошибка static void func2() const;// Ошибка static void func3() volatile;Последнее, что стоит упомянуть: к статическим членам можно обращаться независимо, то есть к ним можно обращаться без создания какого-либо экземпляра объекта. };

Автор: SDMrFeng

Оригинал: https://blog.csdn.net/tobefxz/article/details/14109697

Pycharm: импорт пакетов и модулей Python