телевизори. Конзоли. Проектори и аксесоари. Технологии. Цифрова телевизия

Какво означава статичен в c. Статични методи в Java (статични методи). Споделяне на елемент от данни

След това можем да получим достъп до тях директно чрез името на класа и оператора за разрешаване на обхвата. Но какво ще стане, ако статичните членски променливи са частни? Разгледайте следния код:

В този случай не можем да получим директен достъп до Anything::s_value от main(), тъй като този член е частен. Обикновено частните членове на клас се осъществяват чрез публични методи. Докато бихме могли да създадем обикновен метод за достъп до s_value, тогава ще трябва да създадем обект от този клас, за да използваме метода! Има по-добър вариант: можем да направим метода статичен.

Подобно на статичните членски променливи, статични методине са обвързани с нито един клас обект. Ето примера по-горе, но със статичен метод:

class Anything ( private: static int s_value; public: static int getValue() ( return s_value; ) // статичен метод ); int Anything::s_value = 3; // дефиниция на статична променлива член на класа int main() ( std::cout<< Anything::getValue() << "\n"; }

Тъй като статичните методи не са обвързани с конкретен обект, те могат да бъдат извикани директно чрез името на класа и оператора за разрешаване на обхвата, както и чрез обектите на класа (но това не се препоръчва).

Статичните методи нямат указател *this

Статичните методи имат две интересни характеристики. Първо, тъй като статичните методи не са обвързани с обект, те нямат ! Това има смисъл, тъй като указателят *this винаги сочи към обекта, върху който работи методът. Статичните методи може да не работят чрез обект, така че указателят *this не е необходим.

Второ, статичните методи имат директен достъп до други статични членове (променливи или функции), но не могат да осъществяват достъп до нестатични членове. Това е така, защото нестатичните членове принадлежат към обекта на класа, но статичните методи не принадлежат!

Още един пример

Статичните методи могат да бъдат дефинирани извън тялото на класа. Това работи по същия начин, както при обикновените методи. Например:

#включи class IDGenerator ( private: static int s_nextID; // декларация на статична членска променлива public: static int getNextID(); // декларация на статичен метод); // Дефиницията на статична членска променлива е извън тялото на класа. Моля, обърнете внимание, че тук не използваме статичната ключова дума // Започнете да генерирате идентификатори от 1 int IDGenerator::s_nextID = 1; // Дефиницията на статичен метод е извън тялото на класа. Моля, обърнете внимание, че тук не използваме статичната ключова дума int IDGenerator::getNextID() ( return s_nextID++; ) int main() ( for (int count=0; count< 4; ++count) std::cout << "The next ID is: " << IDGenerator::getNextID() << "\n"; return 0; }

#включи

клас IDGenerator

лично:

статичен int s_nextID; // декларация на статична променлива член

публичен:

static int getNextID(); // декларация на статичен метод

// Започнете да генерирате ID от 1

int IDGenerator::s_nextID = 1;

int IDGenerator::getNextID() (връща s_nextID++;)

int main()

за (int count = 0; count< 4 ; ++ count )

std::cout<< "The next ID is: " << IDGenerator :: getNextID () << "\n" ;

връщане 0;

Резултатът от изпълнението на горната програма:

Следващият ID е: 1
Следващият ID е: 2
Следващият ID е: 3
Следващият ID е: 4

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

Предупреждение за класове с всички статични членове

Бъдете внимателни, когато пишете класове с всички статични членове. Докато такива "чисто статични класове" могат да бъдат полезни, те също имат своите недостатъци.

Първо, тъй като всички статични членове се създават само веднъж, не може да има множество копия на „чисто статичен клас“ (без клониране на класа и след това преименуване). Например, ако имаме нужда от два независими обекта от класа IDGenerator, това няма да бъде възможно чрез „чисто статичен“ клас.

C++ не поддържа статични конструктори

Ако можете да инициализирате обикновена членска променлива чрез , тогава логично трябва да можете да инициализирате статични членски променливи чрез статичен конструктор. И докато някои съвременни езици поддържат статични конструктори точно за тази цел, C++, за съжаление, не е един от тях.

Ако вашата статична променлива може да бъде инициализирана директно, тогава няма нужда от конструктор: можете да дефинирате статична членска променлива, дори ако е частна. Правим това в примера по-горе с s_nextID. Ето още един пример:

class Something (public: static std::vector s_mychars; ); std::vector Something::s_mychars = ( "o", "a", "u", "i", "e"); // дефиниране на статична членска променлива

клас Нещо

публичен:

статичен std::vector< char >s_mychars;

std::vector< char >Нещо :: s_mychars = ( "o" , "a" , "u" , "i" , "e" ) ; // дефиниране на статична членска променлива

Ако инициализирането на вашата статична членска променлива изисква изпълнение на код (като цикъл), тогава има няколко различни начина да го направите. Следният метод е най-добрият:

#включи #включи class Something ( private: static std::vector s_mychars; public: class _nested // дефиниране на вложен клас, наречен _nested ( public: _nested() // конструкторът _nested инициализира нашата статична членска променлива ( s_mychars.push_back("o"); s_mychars.push_back("a"); s_mychars.push_back ("u"); s_mychars.push_back("i"); s_mychars.push_back("e"); )); // Статичен метод за извеждане на s_mychars static void getSomething() ( for (auto const &element: s_mychars) std::cout<< element << " "; } private: static _nested s_initializer; // используем статический объект класса _nested для гарантии того, что конструктор _nested выполнится }; std::vectorНещо::s_mychars; // дефинираме нашата статична членска променлива Something::_nested Something::s_initializer; // дефинираме нашия статичен s_initializer, който ще извика конструктора _nested за инициализиране на s_mychars int main() ( Something::getSomething(); return 0; )

#включи

#включи

клас Нещо

лично:

статичен std::vector< char >s_mychars;

публичен:

клас_вложен // дефиниране на вложен клас с име _nested

публичен:

вложен() // конструкторът _nested инициализира нашата статична членска променлива

s_mychars. тласък_назад("o");

s_mychars. тласък_назад("а");

s_mychars. тласък_назад("u");

s_mychars. push_back("i");

s_mychars. push_back("e");

Повечето C++ ключови думи правят едно нещо. Използвате int, за да декларирате целочислена променлива, когато функция връща цяло число или приема цяло число като аргумент. Използвате оператора new, за да разпределите памет, а оператора delete, за да я освободите. Можете да използвате const, за да посочите, че стойността на променлива не може да бъде променена. По ирония на съдбата ключовата дума static, въпреки че означава „непроменим“, има множество (и очевидно несвързани) приложения. Ключовата дума static може да се използва в три основни контекста:

  • вътре във функция;
  • вътре в дефиниция на клас;
  • преди глобална променлива във файл, който съставлява многофайлова програма.

Използването на static във функция е най-простото. Това просто означава, че след като една променлива е инициализирана, тя остава в паметта до края на програмата. Можете да мислите за това като за променлива, която запазва стойността си, докато програмата завърши. Например, можете да използвате статична променлива, за да запишете колко пъти е била извикана дадена функция, като просто добавите редовете static int count = 0; и брои++; във функция. Тъй като count е статична променлива, редът static int count = 0; ще се изпълнява само веднъж. Всеки път, когато функцията бъде извикана, count ще има последната дадена стойност.

Можете също да използвате static по начин, който предотвратява повторното инициализиране на променливата вътре в цикъла. Например в следния код променливата number_of_times ще бъде равна на 100, въпреки че редът static int number_of_times = 0; е вътре в цикъл, където вероятно трябва да се изпълнява всеки път, когато програмата достигне цикъла. Сложната част е, че ключовата дума static предотвратява повторното инициализиране на променливата. Едно от нещата при използването на ключовата дума static е, че тя автоматично настройва променливата на нула за вас - но не разчитайте на това (това прави намеренията ви неясни).

For(int ix=0; ix< 10; ix++) { for(int iy = 0; iy < 10; iy++) { static int number_of_times = 0; number_of_times++; } }

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

Второто използване на static е вътре в дефиниция на клас. Въпреки че повечето променливи, декларирани в рамките на клас, могат да имат различна стойност във всеки екземпляр на класа, статичните полета на класа ще имат едно и също значение за всички екземпляри на даден клас и дори не е необходимо да създавате екземпляр на този клас. Полезно е да мислите за статичните променливи на класа като съдържащи информацията, необходима за създаване на нови обекти (например във фабрика за класове). Например, ако искате да номерирате екземпляри на клас, можете да използвате статична променлива, за да следите последния използван номер. Важно е да се отбележи, че добра практика при използване на статични класови променливи е да се използва class_name::x; , а не instance_of_class.x; . Това помага да се напомни на програмиста, че статичните променливи не принадлежат към един екземпляр на клас и че не е нужно да създавате екземпляр на този клас. Както може би сте забелязали, можете да използвате оператора за обхват, ::, за достъп до static, когато го осъществявате чрез името на класа.

Важно е да имате предвид, когато отстранявате грешки или внедрявате програма, използвайки static, че не можете да я инициализирате вътре в клас. Всъщност, ако решите да напишете целия код на класа в заглавен файл, вие дори няма да можете да инициализирате статична променлива в заглавния файл; направете това в .cpp файла. Освен това трябва да инициализирате статичните членове на класа или те няма да бъдат в обхвата. (Синтаксисът е малко странен: тип class_name::static_variable = value .)

Можете също така да имате статични функции на класа. Статичните функции са функции, които не изискват екземпляр на клас и се извикват по същия начин, по аналогия със статичните променливи, с името на класа, а не с името на обекта. Например a_class::static_function(); , а не an_instance.function(); . Статичните функции могат да работят само върху статични членове на клас, тъй като те не се отнасят до конкретни екземпляри на класа. Статичните функции могат да се използват за промяна на статичните променливи, за проследяване на техните стойности - например можете да използвате статична функция, ако решите да използвате брояч, за да дадете на всеки екземпляр от клас уникален идентификатор.

Например, можете да използвате следния код:

Клас потребител ( private: int id; static int next_id; public: static int next_user_id() ( next_id++; return next_id; ) // други методи за потребителския клас user() // конструктор на клас ( id = user::next_id++; / / или извикване на метод, id = user.next_user_id(); ) ); int user::next_id = 0;

Имайте предвид, че трябва да включите типа на статичната променлива, когато я задавате!

Потребител a_user;

ще зададе ID на следващия ID номер, който не се използва от друг потребителски обект. Имайте предвид, че е добър стил да декларирате идентификатор като константа.

Последната употреба на static е като глобална променлива в кодов файл. В този случай използването на static показва, че изходният код в други файлове, които са част от проекта, няма достъп до променливата. Само код в същия файл може да види променливата (нейният обхват е ограничен до файла). Тази техника може да се използва за моделиране на обектно-ориентиран код, тъй като ограничава видимостта на променливите и по този начин помага да се избегнат конфликти при именуване. Този начин на използване на static е реликва от C.

Последна актуализация: 25.12.2018

В допълнение към обикновените полета, методи и свойства, един клас може да има статични полета, методи и свойства. Статичните полета, методи, свойства се отнасят за целия клас и за достъп до такива членове на класа не е необходимо да се създава екземпляр на класа. Например:

Клас акаунт ( публичен статичен десетичен бонус = 100; публичен десетичен десетичен totalSum; публичен акаунт (десетична сума) ( totalSum = сума + бонус; ) ) клас програма ( статичен void Main(string args) ( Console.WriteLine(Account.bonus); / / 100 Account.bonus += 200; Account account1 = new Account(150); Console.WriteLine(account1.totalSum); // 450 Account account2 = new Account(1000); Console.WriteLine(account2.totalSum); // 1300 Console.ReadKey(); ) )

В този случай класът Account има две полета: bonus и totalSum. Бонусното поле е статично, така че съхранява състоянието на класа като цяло, а не на отделен обект. И така можем да се позоваваме на това поле по име на клас:

Console.WriteLine(Account.bonus); Account.bonus += 200;

На ниво памет за статични полета ще бъде създадено място в паметта, което ще бъде общо за всички обекти от класа.

В този случай паметта за статични променливи се разпределя дори ако не са създадени обекти от този клас.

Статични свойства и методи

По подобен начин можем да създаваме и използваме статични методи и свойства:

Клас акаунт ( публичен акаунт (десетична сума, десетична ставка) ( ако (сума< MinSum) throw new Exception("Недопустимая сумма!"); Sum = sum; Rate = rate; } private static decimal minSum = 100; // минимальная допустимая сумма для всех счетов public static decimal MinSum { get { return minSum; } set { if(value>0) minSum = стойност; ) ) публична десетична сума ( get; private set; ) // сума по сметката public decimal Rate ( get; private set; ) // лихвен процент // изчисляване на сумата по сметката след определен период при определен процент public статичен десетичен GetSum(десетичен сбор, десетична скорост, int период) ( десетичен резултат = сума; за (int i = 1; i<= period; i++) result = result + result * rate / 100; return result; } }

Променливата minSum, свойството MinSum и методът GetSum са дефинирани тук с ключовата дума static, което означава, че са статични.

Променливата minSum и свойството MinSum представляват минималната сума, която е разрешена за създаване на фактура. Този индикатор не се отнася за конкретен акаунт, а се отнася за всички акаунти като цяло. Ако променим този индикатор за един акаунт, той трябва да се промени и за другия акаунт. Тоест, за разлика от свойствата Sum и Rate, които съхраняват състоянието на даден обект, променливата minSum съхранява състоянието за всички обекти от даден клас.

Същото е и с метода GetSum - изчислява сумата по сметката след определен период при определен лихвен процент за определена първоначална сума. Извикването и резултатът от този метод не зависят от конкретен обект или неговото състояние.

По този начин променливите и свойствата, които съхраняват състояние, общо за всички обекти от даден клас, трябва да бъдат дефинирани като статични. И също така методите, които дефинират поведение, общо за всички обекти, също трябва да бъдат декларирани като статични.

Статичните членове на клас са общи за всички обекти от този клас, така че те трябва да бъдат посочени с името на класа:

Моля, обърнете внимание, че статичните методи имат достъп само до статични членове на клас. Нямаме достъп до нестатични методи, полета, свойства вътре в статичен метод.

Статичните полета често се използват за съхраняване на броячи. Например, да кажем, че имаме потребителски клас и искаме да имаме брояч, който ни позволява да знаем колко потребителски обекта са създадени:

Клас Потребител ( private static int counter = 0; public User() ( counter++; ) public static void DisplayCounter() ( Console.WriteLine($"Created (counter) User objects"); ) ) class Program ( static void Main(string) args) ( Потребител потребител1 = нов потребител(); потребител потребител2 = нов потребител(); потребител потребител3 = нов потребител(); потребител потребител4 = нов потребител(); потребител потребител5 = нов потребител(); потребител.DisplayCounter(); / / 5 Console.ReadKey(); ) )

Статичен конструктор

В допълнение към обикновените конструктори, класът може да има и статични конструктори. Статичните конструктори имат следните отличителни характеристики:

    Статичните конструктори не трябва да имат модификатор за достъп и не приемат параметри

    Както при статичните методи, статичните конструктори не могат да използват ключовата дума this за препращане към текущия обект на класа и имат достъп само до статични членове на класа

    Статичните конструктори не могат да бъдат извикани ръчно в програма. Те се изпълняват автоматично още при първото създаване на обект от даден клас или при първия достъп до неговите статични членове (ако има такива).

Статичните конструктори обикновено се използват за инициализиране на статични данни или за извършване на действия, които трябва да бъдат извършени само веднъж

Нека да дефинираме статичен конструктор:

Class User ( static User() ( Console.WriteLine("Първият потребител е създаден"); ) ) class Program ( static void Main(string args) ( User user1 = new User(); // статичният конструктор ще работи тук Потребител потребител2 = нов потребител(); Console.Read(); ) )

Статични класове

Статичните класове се декларират със статичния модификатор и могат да съдържат само статични полета, свойства и методи. Например, ако класът Account има само статични променливи, свойства и методи, тогава той може да бъде деклариран като статичен:

Статичен клас Account ( private static decimal minSum = 100; // минимално позволена сума за всички акаунти public static decimal MinSum ( get ( return minSum; ) set ( if(value>0) minSum = value; ) ) // преброяване на сумата в сметката след определен период с определен процент public static decimal GetSum(десетична сума, десетична скорост, int период) ( десетичен резултат = сума; за (int i = 1; i<= period; i++) result = result + result * rate / 100; return result; } }

В C# илюстративен пример за статичен клас е класът Math, който се използва за различни математически операции.

Урок 25. Статични функции и членове от данни

Досега всеки създаден от вас обект имаше свой собствен набор от елементи от данни. В зависимост от целта на вашето приложение може да има ситуации, при които обекти от един и същи клас трябва да споделят един или повече елементи от данни. Да предположим например, че пишете програма за заплати, която проследява работните часове за 1000 служители. За да определи данъчната ставка, програмата трябва да знае условията, в които работи всеки служител. Нека използваме класова променлива за това състояние_на_работа.Въпреки това, ако всички служители работят при еднакви условия, вашата програма може да споделя този елемент от данни между всички обекти от тип служител.Така вашата програма намалява количеството необходима памет, като изхвърля 999 копия на една и съща информация. За да споделите елемент от клас, трябва да декларирате този елемент като статичен (статичен).Този урок обхваща стъпките, които трябва да следвате, за да споделите елемент от клас между множество обекти. До края на този урок ще сте усвоили следните основни концепции:

    C++ ви позволява да имате обекти от същия тип, които споделят един или повече членове на клас.

    Ако вашата програма присвои стойност на споделен елемент, тогава всички обекти от този клас веднага имат достъп до тази нова стойност.

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

    След като програмата е декларирала елемент от класа като статичентой трябва да декларира глобална променлива (извън дефиницията на класа), която съответства на този споделен член на класа.

    Вашите програми могат да използват ключовата дума статиченза да направи метод на клас извикваем, докато програмата може все още да не е декларирала никакви обекти от този клас.

СПОДЕЛЯНЕ НА ЕЛЕМЕНТ ДАННИ

Обикновено, когато създавате обекти от определен клас, всеки обект получава свой собствен набор от членове с данни. Възможно е обаче да има ситуации, при които обекти от един и същи клас трябва да споделят един или повече елементи от данни (статичен напрелементи от данни). В такива случаи декларирайте елементите от данни като обща тиняИ частен,и след това предшествайте типа с ключовата дума статиченкакто по-долу:

частен: статичен int споделена_стойност;

След като декларирате класа, трябва да декларирате елемента като глобална променлива извън класа, както е показано по-долу:

int class_name::shared_value;

Следната програма SHARE_IT.CPP дефинира класа поредица от книги,елемент за споделяне брой_страници,което е еднакво за всички обекти (книги) от класа (серията). Ако програма промени стойността на този елемент, промяната веднага се отразява във всички обекти на класа:

#включи

#включи

класна книга_серия

( public: book_series(char *, char *, float); void show_book(void); void set_pages(int) ; private: static int page_count; char title; char author[64]; float price; );

int book_series::page__count;

void book_series::set_pages(int pages)

( page_count = страници; )

book_series::book_series(char *заглавие, char *автор, плаваща цена)

( strcpy(book_series::title, title); strcpy(book_series::author, автор); book_series::price = цена; )

void book_series:: show_book (void)

( cout<< "Заголовок: " << title << endl; cout << "Автор: " << author << endl; cout << "Цена: " << price << endl; cout << "Страницы: " << page_count << endl; }

( book_series programming("Да се ​​научим да програмираме на C++", "Jamsa", 22.95); book_series word("Да се ​​научим да работим с Word за Windows", "Wyatt", 19.95); word.set_pages(256); programming.show_book ( ); word.show_book() ; cout<< endl << "Изменение page_count " << endl; programming.set_pages(512); programming.show_book(); word.show_book(); }

Както можете да видите, класът декларира брой_страницикак статично вътр.Веднага след дефиницията на класа програмата декларира елемент брой_страницикато глобална променлива. Когато една програма промени елемент брой_страници,промяната веднага се отразява във всички обекти на класа книга_поредица.

Споделяне на членове на класа

В зависимост от вашата програма може да има ситуации, в които трябва да споделите определени данни в множество екземпляри на обект. За да направите това, декларирайте елемента като статичен. След това декларирайте този елемент извън класа като глобална променлива. Всички промени, които вашата програма прави в този елемент, ще бъдат незабавно отразени в обектите от този клас.

Използване на елементи с атрибутиpublic static if обекти не съществуват

Както току-що научихте, когато декларирате елемент от клас като статичентози елемент се споделя от всички обекти от даден клас. Възможно е обаче да има ситуации, при които програмата все още не е създала обекта, но трябва да използва елемента. За да използвате елемент, вашата програма трябва да го декларира като публиченИ статичен.Например следната програма USE_MBR.CPP използва елемента брой_странициот класа поредица от книги,дори ако обекти от този клас не съществуват:

#включи

#включи

класна книга_серия

( public: static int page_count; private: char title; char author; float price;);

int book_series::page_count;

void main(void) ( book_series::page_count = 256; cout<< "Текущее значение page_count равно " << book_series::page_count << endl; }

В този случай, тъй като класът дефинира елемент от класа брой_страницикак публиченпрограма може да има достъп до този елемент от класа, дори ако обектите на класа книга_поредицане съществува.

ИЗПОЛЗВАНЕ НА СТАТИЧНИ ЕЛЕМЕНТНИ ФУНКЦИИ

Предишната програма илюстрира използването статиченелементи от данни. По същия начин C++ ви позволява да дефинирате статиченелемент функции (методи). Ако създавате статиченметод, вашата програма може да извика такъв метод, дори ако обектите не са създадени. Например, ако даден клас съдържа метод, който може да се използва за данни извън класа, можете да създадете този метод статичен.По-долу е класът менюкойто използва последователността esc на драйвера ANSI, за да изчисти екрана на дисплея. Ако имате инсталиран драйвер ANSI.SYS на вашата система, можете да използвате метода чист_екранза почистване на екрана. Тъй като този метод е деклариран като статичен,програмата може да го използва дори ако обектите са от тип менюне съществува. Следната програма CLR_SCR.CPP използва метода чист_екранЗа да изчистите екрана на дисплея:

#включи

( public: static void clear_screen(void); // Тук трябва да има други методи private: int number_of_menu_options; );

void меню :: clear_screen (void)

( cout<< "\033" << "}

Свързани публикации