Разбираем конструкции языка C++ на примере работы в Microsoft Visual Studio 2008 Урок 1 Основные операторы языка C++ |
||
Данный небольшой урок является введением в программирование на C++ в MSVS 2008 Вам нужно иметь установленную среду Microsoft Visual Studio 2005 или 2008 (можно триал) |
||
[назад] [далее] [к содержанию] | ||
Мы рассматриваем основные конструкции языка C++ на примере работы в Microsoft Visual Studio 2008 | ||
В предыдущем уроке мы создали небольшой калькулятор. Этот урок позволил нам бегло познакомиться с некоторыми из конструкций языка C++ и некоторыми функциями. | ||
Теперь пришло время начать освещение основных базовых конструкций языка C++ на конкретных примерах Основные операторы (statements) языка - этой теме посвящен следующий раздел MSVS 2008 Documentation (далее просто Help) - Development Tools and Languages > Visual Studio > Visual C++ > Reference > C/C++ Languages - использование операторов помеченных меткой; - построение выражений; - пустой оператор; - операторы наполнения (логические скобки); - операторы выбора (ветвлений); - операторы организации циклов; - операторы перехода (передачи управления); - операторы объявления переменных; - операторы обработки исключений; |
||
- использование операторов помеченных меткой; метка (label) это особый тип идентификатора, который позволяет пометить нужную строку кода в программе содержащую исполнимый оператор, а затем использовать имя этой метки в операторах передачи управления и выбора. Пример из MSVS 2008 Help //
labels_with_goto.cpp cout << "testing" << endl;
Test2: |
||
данный пример рассчитан на консольное приложение. Как видим в отличие от delphi метка не требует предварительного объявления. Достаточно лишь указать допустимый идентификатор метки (Слово начинающееся с буквы) и закончить его двоеточием указав в нужном месте программы. Метка всегда указывает на исполнимый оператор! Даже если в этом месте будет записана строка комментария например так - Test2: // будет считаться, что метка указывает именно на исполнимый оператор, все незначащие строки (комментарии) при этом игнорируются. |
||
- построение выражений; операторы выражений приводят к вычислению какого-либо результата, никакой передачи управления или итерации при этом не происходит. Выражение должно завершаться точкой с запятой. Примеры выражений: coord_x = coord_x + 10 * MoveSpeed * TimeCounter; absc2 = sqrt( abs ( c1 ) ); |
||
- пустой оператор; Это строка содержащая лишь точку с запятой, т.е. ; |
||
- операторы наполнения (логические скобки); это пара фигурных скобок { и }. Применяется как блок операторов там, где вместо одного оператора нужно использовать целую группу. Блок может не содержать ни одного оператора вообще, тогда это просто пустой блок. Пример: if(
Amount > 100 )
}
Все переменные объявленные внутри блока без префикса static являются локальными для данного блока. |
||
- операторы выбора (ветвлений); оператор switch - оператор ветвлений мы уже сталкивались с этим оператором в предыдущем уроке, когда писали пример простейшего калькулятора форма записи этого оператора switch
( expression ) выражение в скобках должно давать целочисленный результат каждый оператор case позволяет выполнять заданный блок кода в зависимости от указанного целочисленного значения блок кода при default выполняется когда значению выражения не соответствует ни одна строка с оператором case Пример: //
switch_statement2.cpp Если Вы программировали на Delphi, то заметите, что аналогом оператора switch в delphi является оператор case. Т.е. switch в C++ и case в Delphi это одно и то же. Отличия состоят в синтаксисе, наличие строки default (в C++) и применении оператора break (в C++). к операторам выбора также относится оператор условия if if
( expression ) как видим он похож на использование оператора if в delphi, с тем лишь отличием, что слово then не используется. Пример: //
if_else_statement.cpp int
main() { Поэтому в C++ аналогом delphi-конструкции if SomeObject <> nil then {...} else {...}; будет являться if SomeObject { } else { } |
||
- операторы организации циклов; служат для выполнения одной и той же группы операторов итеративно. Различают циклы с предусловием while, пост условием do и цикл с заданным количеством итераций for while
( expression ) в цикле while группа операторов statement выполняется пока значение выражения expression не достигнет нуля Пример: кусок кода на delphi7 aCurrentCharnum
:= 0; при условии, что требуемые переменные объявлены, на C++ будет выглядеть так int
aCurrentCharnum = 0; |
||
Обязательно напишите и проверьте работу этого кода в приложении наподобие HelloWorldCLR | ||
оператор цикла с пост-условием do do оператор do является аналогом цикла repeat..until в delphi Пример: int
i = 0;
do по нажатию на кнопку на ее поверхности выводится 012 |
||
цикл for for
( init-expression ; cond-expression ; loop-expression ) про цикл for в документации по MSVS рассказано много интересных вещей, так что за подробностями обратитесь к ней. Кратко же использование цикла for выглядит так - Пример: String^ SomeStr = L"";
for (int i = 0; i<5; i++) на поверхности кнопки появляется текст 01234 |
||
- операторы перехода (передачи управления); к операторам перехода относятся операторы изменяющие обычный последовательный ход исполнения программы - break, continue, return, goto оператор break аналогичен оператору break в delphi - служит для немедленного выхода из цикла for, while и do, кроме того используется для выхода из ветви оператора switch (в delphi для этих целей не применяется) оператор continue аналогичен оператору continue в delphi - служит для немедленного перехода к следующей итерации цикла for, while и do оператор return return [expression] служит для возврата из функции или процедуры. Если выполняется возврат из функции, то значение выражения expression возвращается в качестве результата. Для функций void (процедур) никакого результата не возвращается. Для возврата из процедуры (функция с результатом void) специального вызова return не требуется. Выполнение процедуры будет закончено там, где кончаются ее логические скобки. оператор goto служит для безусловной передачи управления на указанную метку - goto identifier ; Примеры: для корректного выполнения примера в приложении Windows Forms добавьте на форму поле ввода textBox1 int somenum = Convert::ToInt32(textBox1->Text);
for (int i = somenum; i < (somenum+3); i++) данный код добавьте в обработчик нажатия на кнопку button1 размещенную на форме Form1 по нажатию на кнопку в поле textBox1 вместо введенного значения появляется значение на 1 большее в случае когда поля textBox1 пусто вырабатывается исключительная ситуация. Ее можно избежать, если для свойства Text у textBox1 задать любое числовое значение, которое будет значением по умолчанию //
continue_statement.cpp
printf_s("after the do loop\n"); //
return_statement2.cpp int
max ( int a, int b ) int
main()
printf_s("\n%d is bigger\n", max( nOne, nTwo )); //
goto_statement.cpp
for ( i = 0; i < 10; i++ )
// This message does not print: |
||
в следующем уроке мы рассмотрим операторы объявления переменных и обработки исключений | ||
[назад] [далее] [к содержанию] |
автор: Тимонин Андрей
дата публикации на сайте Мега Информатик: 18.11.2012
Добро пожаловать в цикл моих уроков посвященных программированию.
На написание этой статьи меня вдохновил блог о создании игр с нуля, который можно посмотреть по следующей ссылке mindillusion.ru.
Здесь мы продолжаем работать с Direct X9 и создадим свое приложение на основе созданного нами класса.
Результат наших действий будет такой, как на скриншоте.
И так, перейдем к делу... Для начала, нам необходимо создать окно. Используем Win32 Api фунции. Мой базовый класс для упрощения создания таких приложений.
class BaseWindowClass {
protected:
WNDCLASS baseWndClass;
HWND baseHWindow;
MSG baseMessage;
float dx, dy; //смещение координат Direct3D относительно координат окна
float clientWidth, clientHeight; //длина и высота окна
public:
//конструктор
BaseWindowClass();
//деструктор
virtual ~BaseWindowClass();
/*Этот метод создает окно.
Параметры:
hInstance - идентификатор приложения
szTitle - заголовок приложения
iWidth - ширина окна
iHeight - высота окна
*/
bool Create(HINSTANCE hInstance, LPCWSTR szTitle,
DWORD iStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE,
int iWidth = CW_USEDEFAULT,
int iHeight = CW_USEDEFAULT);
//оконная процедура
static LRESULT CALLBACK WndProc(HWND hWindow, UINT iMessage,
WPARAM wParam, LPARAM lParam);
//Этот метод запускает цикл обработки сообщений
void Run();
//Этот метод выполняет обработку сообщений
virtual bool MessageHandler(UINT iMessage, WPARAM wParam,
LPARAM lParam);
//Абстрактный метод. Предназначен для рисования в окне.
//Вызывается в цикле сообщений.
virtual void Render(float ElapseTime) = 0;
virtual void FrameMove(float ElapseTime)=0;
//этот метод выполняет инициализацию Direct3D
bool initD3D();
//этот метод настраивает устройство Direct3D
void setMatricesAndRenderStates();
};
А теперь посмотрим на реализацию методов.
BaseWindowClass::BaseWindowClass() {}
//-----------------------------------------------------------------------
BaseWindowClass::~BaseWindowClass()
{
//удаляем класс окна
UnregisterClass(L"BaseWindow", baseWndClass.hInstance);
}
Создание окна осущесттвляется таким образом.
bool BaseWindowClass::Create(HINSTANCE hInstance, LPCWSTR szTitle,
DWORD iStyle, int iWidth, int iHeight)
{
//заполняем структуру с параметрами класса окна
baseWndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
baseWndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SPACE));
baseWndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
baseWndClass.hInstance = hInstance;
baseWndClass.lpfnWndProc = WndProc;
baseWndClass.lpszClassName = L"Base Window";
baseWndClass.lpszMenuName = NULL;
baseWndClass.cbClsExtra = 0;
baseWndClass.cbWndExtra = 0;
baseWndClass.style = 0;
//пробуем зарегистрировать класс окна
if(!RegisterClass(&baseWndClass))
{
//если не получилось, генерируем исключение
Space::ExceptionBase e(CLASSREGISTRATIONERROR, L"Не могу зарегистрировать класс");
throw e;
}
//пробуем создать окно
baseHWindow = CreateWindow(L"Base Window", szTitle, iStyle,
CW_USEDEFAULT, CW_USEDEFAULT,
iWidth, iHeight, NULL, NULL,
hInstance, (void*)this);
//в случае неудачи генерируем исключение
if(baseHWindow == NULL)
{
Space::ExceptionBase e(WINDOWCREATIONERROR, L"Не могу создать окно");
throw e;
}
//пробуем установить заданный текст в заголовке окна
if(!SetWindowText(baseHWindow, szTitle))
{
//если не получилось, генерируем исключение
Space::ExceptionBase e(SETTITLEERROR, L"Не могу изменить текст в заголовке окна");
throw e;
}
return 0;
}
Окно создано. Пришло время узнать, как же будем происходить рендер. И где будет формироваться каждый кадр нашего приложения.
Операционная система Windows общается со своими клиентскими приложениями посредством сообщений. А значит, нам необходимо обрабатывать эти сообщения и между делом выводить наше, сформированное в заднем буфере изображение на канву окна.
CALLBACK Функция WndProc выглядит у нас таким образом
LRESULT CALLBACK BaseWindowClass::WndProc(HWND hWindow,
UINT iMessage, WPARAM wParam, LPARAM lParam)
{
//создаем указатель на данный экземпляр класса
BaseWindowClass *baseWnd = NULL;
bool beProcessed = false;
//обрабатываем принятое сообщение
switch(iMessage)
{
//это сообщение отправляется при создании окна
case WM_NCCREATE:
//изменяем атрибут данного окна на значение, указанное в параметре
//(lParam) сообщения (указатель на данные, которые используются для
//создания окна)
SetWindowLong(hWindow, GWL_USERDATA,
(long)(LPCREATESTRUCT(lParam)->lpCreateParams));
break;
default:
//определяем указатель на данный экземпляр класса
baseWnd = (BaseWindowClass*)GetWindowLong(hWindow,
GWL_USERDATA);
if(baseWnd != NULL)
{
//вызываем обработчик сообщений данного класса
beProcessed = baseWnd->MessageHandler(iMessage,
wParam, lParam);
}
break;
}
//если принятое сообщение не было обработано...
if(beProcessed == false)
{
//... выполняем стандартную обработку
return DefWindowProc(hWindow, iMessage, wParam, lParam);
}
return 0;
}
Цикл обработки сообщений, пока не поймаем событие закрытия окна.
void BaseWindowClass::Run()
{
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
//входим в цикл обработки сообщений
while( msg.message!=WM_QUIT )
{
//читаем очередное сообщение
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
//обрабатываем его
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
float ElapseTime;
ElapseTime = Space::getElapsedTime();
//перерисовываем окно
FrameMove(ElapseTime);
Space::Graphics& gr = Space::Graphics::get();
if (!FAILED(gr.StartRender(0x00000000)))
{
Render(ElapseTime);
// закончили рендер
gr.EndRender();
}
else
gr.Reset();
}
}
}
Окно создано, события обрабатываются, осталось только создать наше Direct3D устройство и настроить матрицы проекций. Смотрим далее.
//этот метод выполняет инициализацию Direct3D и объектов игры
bool BaseWindowClass::initD3D()
{
//определяем размер клиентской части окна
RECT clientRect;
GetClientRect(baseHWindow, &clientRect);
//определяем смещение координат Direct3D относительно оконных координат
dx = (float)((clientRect.right - clientRect.left)/2);
dy = (float)((clientRect.bottom - clientRect.top)/2);
//сохраняем размер окна
clientWidth = dx * 2;
clientHeight = dy * 2;
// Инициализируем графику
if (!Space::Graphics::get().Init(baseHWindow, clientWidth, clientHeight))
return FALSE;
return TRUE;
}
Устройство создано, осталось его настроить.
//этот метод настраивает устройство Direct3D
void BaseWindowClass::setMatricesAndRenderStates()
{
Space::Graphics& gr = Space::Graphics::get();
//начинаем рендер. Очищаем буфер кадра и заливаем черным цветом
if (!FAILED(gr.StartRender(0x00000000)))
{
// настраиваем рендер-стейты
gr.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
//отключаем освещение
gr.SetRenderState(D3DRS_LIGHTING, FALSE);
//устанавливаем режим отображения как сплошной
gr.SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
gr.SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
//разрешаем Z буфер
gr.SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//настроим Z буфер на запись
gr.SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
D3DXMATRIX mat, matViewProj, matProj, matView;
D3DXMatrixIdentity(&mat);
//определяем размер клиентской части окна
RECT clientRect;
GetClientRect(baseHWindow, &clientRect);
//определяем смещение координат Direct3D относительно оконных координат
dx = (float)((clientRect.right - clientRect.left)/2);
dy = (float)((clientRect.bottom - clientRect.top)/2);
//сохраняем размер окна
clientWidth = dx * 2;
clientHeight = dy * 2;
// матрицы вида и проекции
D3DXMatrixTranslation(&matView, 0, 0, 0);
D3DXMatrixOrthoLH(&matProj, clientWidth, -clientHeight, 0, 10);
// получаем матрицу вида/проекции
D3DXMatrixMultiply(&matViewProj, &matView, &matProj);
// настраиваем фильтрацию текстуры
gr.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
gr.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
gr.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
// включаем альфа-блендинг
gr.SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
gr.SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
gr.SetRenderState( D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA );
}
}
У нас получился абстрактный класс. Для его использование необходимо его конкретизировать и перегрузить виртуальные методы. У нас виртуальными являются
FrameMove и Render. У меня получился такой класс.
class RenderWindow : public BaseWindowClass
{
private:
//этот метод освобождает все созданные объекты
void ReleaseAll();
public:
//конструктор
RenderWindow(void);
//деструктор
virtual ~RenderWindow(void);
//обработчик сообщений пользователя
virtual bool MessageHandler(UINT iMessage, WPARAM wParam,
LPARAM lParam);
//этот метод рисует очередной кадр
virtual void Render(float ElapseTime);
virtual void FrameMove(float ElapseTime);
void CreateScene();
};
Что прописывать в конкретном методе, решать вам. А я покажу, как я создавал этот класс в стандартной функции main - главной функции приложения.
//точка входа в программу
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
LPSTR szCmdLine, INT iCmdShow)
{
try
{
std::setlocale( LC_ALL, ".ACP" );
//создаем экземпляр класса игры
RenderWindow game;
//создаем окно
game.Create(hInst, L"Pandora 1.0b",WS_CAPTION|WS_SYSMENU /*WS_OVERLAPPEDWINDOW*/ | WS_VISIBLE,
800, 600);
//инициализируем Direct3D
game.initD3D();
//устанавливаем матрицы и настраиваем параметры отображения сцены
game.setMatricesAndRenderStates();
game.CreateScene();
//запускаем цикл обработки сообщений
game.Run();
}
//ловим исключения, и выводим сообщения об ошибках
catch(Space::ExceptionBase err)
{
MessageBox(NULL, (const wchar_t*)err, L"Ошибка", MB_ICONERROR);
}
catch(...)
{
MessageBox(NULL, L"Неизвестная ошибка", L"Ошибка", MB_ICONERROR);
}
return 0;
}
На этой позитивной ноте я статью заканчиваю. С уважением, Андрей.
[к содержанию] [другие статьи Тимонина Андрея]
представляем Веселый Буквоежка - онлайн комикс.
Сам верблюд!
[страница 1] [страница 2] [страница 3] [страница 4] [страница 5] [страница 6] [страница 7] [страница 8] [страница 9] [страница 10] [страница 11] [страница 12] [страница 13] [страница 14] [страница 15] [страница 16] [страница 17] [страница 18] [страница 19] [страница 20] [страница 21] [страница 22] [страница 23]