20141014 (C++ class내에 const, friend, static, 시리얼 통신 winapi)

157일차








-----------

C++

-----------



------- const

예제를 통하여 class 내에 const의 기능을 더 확인한다.


예제1)

#include <iostream>


using namespace std;


class SoSimple

{

private:

int num;

public:

SoSimple(int n) : num(n)

{

}


SoSimple & AddNum(int n)

{

num = num + n;

return *this;

}


void ShowData() const

{

cout << "num : " << num << endl;

}

};


int main()

{

const SoSimple obj(7);


// obj.AddNum(20); // error!

obj.ShowData(); // ok!


return 0;

}



obj 객체가 const 로 선언되었기 때문에, AddNum 함수가 const 함수가 아니라서

호출 자체가 에러인 것이다.




예제2)

#include <iostream>


using namespace std;


class SoSimple

{

private:

int num;

public:

SoSimple(int n) : num(n)

{

}


SoSimple & AddNum(int n)

{

num = num + n;

return *this;

}


void SimpleFunc()

{

cout << "SimpleFunc: " << num << endl;

}


void SimpleFunc() const

{

cout << "const SimpleFunc: " << num << endl;

}

};


void YourFunc(const SoSimple & obj) // 인자를 const로 받음

{

obj.SimpleFunc();

}


int main()

{

SoSimple obj1(2);

const SoSimple obj2(7);


obj1.SimpleFunc();

obj2.SimpleFunc();


YourFunc(obj1);

YourFunc(obj2);


return 0;

}


결과



YourFunc(const SoSimple & obj) 함수의 인수 자체가 const로 받았기 때문에

그 안에서 호출되는 객체는 모두 const로 호출된다.










------- friend

class 내에 friend를 선언하면 선언된 class에 private 멤버에 접근이 가능하다.


예제)

#include <iostream>

#include <cstring>


using namespace std;


class Girl; // class도 선언만 가능


class Boy

{

private:

int height;

friend class Girl; // friend 선언 위치는 class 내에 어느 곳이든 가능


public:

Boy(int len) : height(len)

{

}


void ShowYourFriendInfo(Girl & frn); // class 내에서 선언만 해두고 정의는 더 밑에 있다

};


class Girl

{

private:

char phNum[20];


public:

Girl(char * num)

{

strcpy(phNum, num);

}


void ShowYourFriendInfo(Boy & frn); // class 내에서 선언만 해두고 정의는 더 밑에 있다

friend class Boy; // friend 선언 위치는 class 내에 어느 곳이든 가능

};


// 정의가 여기 있는 이유는 Boy class에서 Girl class의 정의가

// 어떤지 모르니 Boy class 내에서 Girl class 에 대한 언급을 할 수가 없기에

// 밑에 다 정의를 해둔 것이다

void Boy::ShowYourFriendInfo(Girl & frn)

{

cout << "Her phone number: " << frn.phNum << endl; // private 멤버에 접근 가능

}


void Girl::ShowYourFriendInfo(Boy & frn)

{

cout << "His height: " << frn.height << endl; // private 멤버에 접근 가능

}


int main()

{

Boy boy(170);

Girl girl("010-1234-5678");


boy.ShowYourFriendInfo(girl);

girl.ShowYourFriendInfo(boy);


return 0;

}





여기서 함수의 접근도 설정할 수 있는데


int main()

{

Boy boy(170);

Girl girl("010-1234-5678");


boy.ShowYourFriendInfo(girl);

girl.ShowYourFriendInfo(boy);


boy.height = 180; // error!


return 0;

}



boy.height = 180; 코드는 에러인데


class Boy

{

private:

int height;

friend class Girl; // friend 선언 위치는 class 내에 어느 곳이든 가능

friend int main(); // 이렇게 main을 추가함


public:

...


위와 같은 방식으로 main()을 추가하면 main도 boy의 friend가 되었기 때문에

에러가 아니게 된다.










------- static 멤버 변수, 함수

class 내 변수에 static 을 붙이면 그 클래스에 그 변수 한 개만 할당되어

그 클래스의 객체들은 그 한 변수를 공유하게 된다.


class smart

{

public:

static int iNum;

};




또 함수에 static을 붙였을 시,

내부 함수나 변수는 static인 함수와 변수만 사용 가능하다.



예제)

#include <iostream>


using namespace std;


class smart

{

public:

static int iNum;

int iNum2;


public:

static void test()

{

cout << "test()" << endl;

iNum = iNum + 1;

// iNum2 = 0; // error! static 변수가 아니라서 사용 못함

}

};

int smart::iNum = 100;


int main()

{

cout << smart::iNum << endl;

smart::test();

cout << smart::iNum << endl;


return 0;

}



한 가지 흥미로운 것은 객체를 생성하지 않았는데 사용 가능하다는 것이다!!!











-------------------------

시리얼 통신 winapi

-------------------------



------- 어제 작성했던 시리얼 통신 DOS 모드로 작성했던 소스를

그래픽 모드로 재작성 하였다.



DOS 모드 소스)

#include <windows.h>

#include <stdio.h>


DWORD WINAPI Thread_Read(LPVOID);


HANDLE hComm;


int main()

{

u_char caString[10] = "하이~";

//char buf;

DWORD dwWritten;

DCB sPState;

COMMTIMEOUTS cTime;

DWORD ThreadID;

HANDLE hThread;


hComm = CreateFile("COM8", GENERIC_READ | GENERIC_WRITE

, 0, NULL, OPEN_EXISTING

, FILE_ATTRIBUTE_NORMAL, 0);


if(INVALID_HANDLE_VALUE == hComm)

{

printf("포트 열 수 없음\n");

return 0;

}


if(0 == SetupComm(hComm, 4096, 3096))

{

printf("버퍼 설정 에러\n");

CloseHandle(hComm);

return 0;

}


if(0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR))

{

printf("버퍼 초기화 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.DCBlength = sizeof(sPState);


if(0 == GetCommState(hComm, &sPState))

{

printf("시리얼 상태 읽기 에러\n");

CloseHandle(hComm);

return 0;

}


sPState.BaudRate = CBR_38400;

sPState.ByteSize = 8;

sPState.Parity = EVENPARITY;

sPState.StopBits = ONESTOPBIT;


cTime.ReadIntervalTimeout = MAXDWORD; // 시간 설정, 블록킹 됐을시 기다리는 시간

cTime.ReadTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.ReadTotalTimeoutConstant = 0;

cTime.WriteTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.WriteTotalTimeoutConstant = 0;


SetCommTimeouts(hComm, &cTime);


if(0 == SetCommState(hComm, &sPState))

{

printf("시리얼 상태 설정 에러\n");

CloseHandle(hComm);

return 0;

}


hThread = CreateThread(NULL, 0, Thread_Read, NULL, 0, &ThreadID);


while(1)

{

caString[0] = getch();

if(0 == WriteFile(hComm, caString, 1, &dwWritten, 0))

{

printf("쓰기 에러\n");

}

else

{

printf("쓰기 성공\n");

}

}


CloseHandle(hComm);


return 0;

}


DWORD WINAPI Thread_Read(LPVOID NotUse)

{

char buf = 0;

DWORD dwRead;


while(1)

{

Sleep(100);

ReadFile(hComm, &buf, 1, &dwRead, NULL);

if(0 != dwRead)

{

printf("[%c] ", buf);

}

}

}






그래픽 모드 소스)

#include <windows.h>

#include "resource.h"


#define ID_EDIT 100


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);

void OpenSPort();

DWORD WINAPI Thread_Read(LPVOID NotUse);

HINSTANCE g_hInst;

LPCTSTR lpszClass=TEXT("Serial");

HWND hMain;


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

,LPSTR lpszCmdParam,int nCmdShow)

{

HWND hWnd;

MSG Message;

WNDCLASS WndClass;

g_hInst=hInstance;


WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=WndProc;

WndClass.lpszClassName=lpszClass;

WndClass.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);

WndClass.style=CS_HREDRAW | CS_VREDRAW;

RegisterClass(&WndClass);


hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,

NULL,(HMENU)NULL,hInstance,NULL);

ShowWindow(hWnd,nCmdShow);


while (GetMessage(&Message,NULL,0,0)) {

TranslateMessage(&Message);

DispatchMessage(&Message);

}

return (int)Message.wParam;

}


HANDLE hComm;

HANDLE hThread;

BOOL bPortOnOff;

HWND hEdit;


LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

u_char caString[128] = "하이~";

DWORD dwWritten;


switch (iMessage)

{

case WM_CREATE:

hMain = hWnd;

hEdit = CreateWindow(TEXT("edit"), NULL, WS_CHILD | WS_VISIBLE

| WS_BORDER | ES_AUTOHSCROLL

, 10, 10, 100, 25, hWnd, (HMENU)ID_EDIT, g_hInst, NULL);

return 0;

case WM_COMMAND:

switch(LOWORD(wParam))

{

case ID_OPEN:

OpenSPort();

break;

case ID_CLOSE:

if(TRUE == bPortOnOff)

{

CloseHandle(hComm);

CloseHandle(hThread);

bPortOnOff = FALSE;

}

break;

case ID_EDIT:

switch(HIWORD(wParam))

{

}

break;

}

return 0;

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}


void OpenSPort()

{

static DCB sPState;

static COMMTIMEOUTS cTime;

DWORD ThreadID;


if(TRUE == bPortOnOff)

{

CloseHandle(hComm);

CloseHandle(hThread);

// return 0;

bPortOnOff = FALSE;

}


hComm = CreateFile(TEXT("COM8"), GENERIC_READ | GENERIC_WRITE

, 0, NULL, OPEN_EXISTING

, FILE_ATTRIBUTE_NORMAL, 0);


if(INVALID_HANDLE_VALUE == hComm)

{

MessageBox(hMain, TEXT("포트 열 수 없음"), TEXT("알림"), MB_OK);

return ;

}


if(0 == SetupComm(hComm, 4096, 3096))

{

MessageBox(hMain, TEXT("버퍼 설정 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


if(0 == PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR))

{

MessageBox(hMain, TEXT("버퍼 초기화 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


sPState.DCBlength = sizeof(sPState);


if(0 == GetCommState(hComm, &sPState))

{

MessageBox(hMain, TEXT("시리얼 상태 읽기 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


sPState.BaudRate = CBR_38400;

sPState.ByteSize = 8;

sPState.Parity = EVENPARITY;

sPState.StopBits = ONESTOPBIT;


cTime.ReadIntervalTimeout = MAXDWORD; // 시간 설정, 블록킹 됐을시 기다리는 시간

cTime.ReadTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.ReadTotalTimeoutConstant = 0;

cTime.WriteTotalTimeoutMultiplier = 0; // 0은 무한 대기

cTime.WriteTotalTimeoutConstant = 0;


SetCommTimeouts(hComm, &cTime);


if(0 == SetCommState(hComm, &sPState))

{

MessageBox(hMain, TEXT("시리얼 상태 설정 에러"), TEXT("알림"), MB_OK);

CloseHandle(hComm);

return ;

}


hThread = CreateThread(NULL, 0, Thread_Read, NULL, 0, &ThreadID);


bPortOnOff = TRUE; // 포트 열기가 완료되었으므로 TRUE

}


DWORD WINAPI Thread_Read(LPVOID NotUse)

{

char tt;

static TCHAR buff[] = TEXT("0x00 ");

DWORD dwRead;


while(1)

{

Sleep(50);

ReadFile(hComm, &tt, 1, &dwRead, NULL);

wsprintf(buff, TEXT("0x%02X "), tt);

if(0 != dwRead)

{

SetWindowText(hEdit, buff);

}

}

}









설정

트랙백

댓글