Категория ‘С/С++’

* Внимание с адреси към локални променливи

Публикувано на 28 ноември 2009 в раздел С/С++.

Съвсем наскоро ми се наложи да оправям много странен бъг в една програма, която ми я прати студент. Накратко – функция на С връщаше адрес към локална променлива. Програмата си работеше перфектно, но… до един момент, в който се записваше нещо ново в стека. Естествено кодът беше достатъчно объркан и зле документиран, а и аз се бях „облъчил“ с Java и ми беше трудно да превключа на „вълна C“. Радвам се обаче, че успях да открия грешката. Съставих и един примерен модел на това, от което трябва да се пазите много, когато работите с указатели: Прочети още…

.

 


* Вектори (std::vector)

Публикувано на 29 ноември 2008 в раздел С/С++.

Досега се стараехме да не използваме готови библиотеки, класове и обекти. За шаблонният клас vector обаче си заслужава да се отдели специално внимание. Векторите са изключително удобен и ефективен заместител на стандартните масиви, като значително спестява ресурси при редица операции. Чрез него имаме възможност за създаване на т.нар. „динамични масиви“.

Първата стъпка е да прибавим класа чрез #include. Вектор се дефинира по следния начин:

#include <vector>
//...
std::vector<тип> v;

Синтаксисът изисква указване на типа елементи във вектора. Често е удобно да използваме typedef при дефиниране на вектори. Например: Прочети още…

.

 


* Шаблони

Публикувано на 29 ноември 2008 в раздел С/С++.

Шаблоните помагат когато искаме да напишем универсална функция, която да може да работи с всякакви типове данни. Синтаксисът е следния:

	template <class <име-на-класа>>;
	<декларация на функция>

Следният пример демонстрира как може да напишем една функция „max“ връщаща по-голямото от две числа, като може да й подадем различни типове данни: Прочети още…

.

 


* Предефиниране на операции

Публикувано на 29 ноември 2008 в раздел С/С++.

В С++ всяка съществуваща унарна или бинарна операция, в която участва поне един обект от даден клас, може да бъде предефинирана от програмиста. Това дава възможност класовете да бъдат интерпретирани, като нови типове данни, които могат да се използват по начин аналогичен на базовите типове. Предефинирането на операции се осъществява чрез операторни функции. Операторната функция е член-функция или приятелска функция на класа, за който тя е дефинирана. Общата форма на една член-функция оператор е следната:

	<тип-резултат> <име-на-клас>::operator<#>(<аргументи>)
	{
		//изпълнявана операция
	}

Типът на връщания резултат най-често е същият като типа на класа, за който е дефиниран операторът. Операторът, който се предефинира, замества # в конструкцията. Когато една операторна член-функция предефинира бинарен оператор, функцията ще приема само един параметър. Този параметър ще получава обекта, който е от дясната страна на оператора. Обектът от лявата страна е този, който генерира обръщението към операторната функция и точно той се предавa неявно на функцията посредством указателя this. Прочети още…

.

 


* Namespace конструкции и нов стил header файлове

Публикувано на 28 ноември 2008 в раздел С/С++.

Namespace е конструкция за езика C++, която представлява разширение на познатите досега класове, а именно – един namespace може да съдържа в себе си набори от класове. По този начин от една страна се получава естествено обединение на обектите, които имат сходна функционалност, а от друга се решава един основен проблем в дизайна на програмите. Представете си, че имате два header файла, които искате да използвате:

	#include "header1.h"
	#include "header2.h"

Нека обаче в тези файлове се съдържат класове с повтарящи се имена: Прочети още…

.

 


* Виртуални функции

Публикувано на 14 ноември 2008 в раздел С/С++.

Виртуалната функция e член-функция, която се дефинира в базовия клас и се предефинира в производния клас. Както и при виртуалните класове ключовата дума е virtual. Когато виртуална функция се предефинира в производен клас, ключовата дума virtual не е необходима. Чрез виртуалните функции се постига също „полиморфизъм по време на изпълнение“. За целта виртуалната функция трябва да бъде извикана посредством указател. Когато указател към базов клас сочи към обект от производен клас, съдържащ виртуална функция, и тази функция се извика посредством указател, С++ решава коя версия на функцията ще бъде извикана въз основа на типа на обекта, сочен от указателя. Именно това решение се взема по време на изпълнение. Прочети още…

.

 


* Виртуални класове

Публикувано на 14 ноември 2008 в раздел С/С++.

При директното наследяване на множество базови класове е възможно един производен клас да наследи многократно даден базов клас. Така обаче може да се получи дублиране на член променливи.

Нека например класа vehicle има два производни класа: motorvehicle (добавя допълнителна информация за типа двигател на превозното срество) и passengervehicle (добавя информация за максималния брой пътници в превозното средство). Ако създадем клас car, който наследява едновременно motorvehicle и passengervehicle, то ние ще получим дублиране на член-променливи, тъй като класа car ще наследи двукратно член-променливите декларирани в класа vehicle.

Многократното наследяване може да се избегне чрез наследяване на базовия клас като виртуален. Това предотвратява присъствието на 2(или повече) копия на базовия клас във всеки следващ индиректен производен клас. Декларацията в този случай ще има вида: Прочети още…

.

 


* Указател към функция

Публикувано на 14 ноември 2008 в раздел С/С++.

Указателите към функции водят до някои много интересни и ефективни програмни техники. Както подсказва името им – това са указатели, които сочат към адреса в паметта, където е записана дадена функция. Тук трябва да отбележим, че указателите към функции не са нововъведение от С++, а са известни още от много компилатори за С. Оказват се особено подходящи при извикване на „callbacks“ и за създаване на събития (events). Callback наричаме функция, която програмистът не е извикал изрично в програмния код. За тяхното изпълнение се грижи друга функция, която е приела указател към нейния адрес. Прочети още…

.

 


* Наследяване

Публикувано на 14 ноември 2008 в раздел С/С++.

Когато един клас наследява друг се използва общата форма:

	class <производен-клас>:<тип-достъп> <име-базов-клас> {
		//...
	};

Типът достъп е една от трите ключови думи: public, private или protected. Разликата между тях е:
– Ако наследяването е тип public, то на производния клас се допуска достъп до членовете на неговия собствен клас, на неговия базов клас и на функции, външни за класовете.
– Ако наследяването е тип protected, то се допуска достъп до членовете на неговия собствен клас, на неговия базов клас, но не се допуска достъп на функции външни за класа.
– Ако наследяването е тип private, то производният клас няма достъп до private елементите на базовия клас и външни функции. Прочети още…

.

 


* Допълнителни задачи към упражнение 4

Публикувано на 14 ноември 2008 в раздел С/С++.

Задача: Дефинирайте клас point с елементи координатите на точка x и y.
– Дефинирайте член-функция show, която отпечатва координатите на точката.
– Дефинирайте член-функция dist, която приема два псевдонима към клас point и връща разстоянието между подадените две точки.
– Предефинирайте член-функцията dist, така че да и предаваме указатели към две точки.

Задача: Дефинирайте два класа – програмист и мениджър. Всеки от класовете да съдържа public елементи име, години и трудов стаж. Като private елементи двата класа да имат елементи заплата и масив от 12 елемента от тип int, в който да се записват броя работни часове за месеците през годината. Напишете:
– Конструктори и деструктори на класовете.
– Приятелска функция за двата класа, която показва кой повече е работил през годината и съответно кой взима по-голяма заплата.

.