5월19일 C++(const, static,virtual,동적바인딩,순수가상함수 API(라디오박스,에디트박스,콤보박스)
const 멤버 함수.
기본적으로 클래스의 함수를 const를 지정하였다.
const는 기본적으로 상수로 강제적으로 상수로 변경하는것과 비슷하다. 그래서 함수를 상수로 변경한다는 과정에 그럼 무엇이 틀려질까? 일단 기본적으로class 안 변수에 i라는 변수에 9를 넣고 함수 안에서 i를 10으로 변경하고 출력했다.
왼쪽 값이 const 함수 관련해서 컴파일 불가 판정이 났따.
하지만 인자로 받은 a에 11로 변경후에... 값을 출력할때 아주 잘되었다.
물론 전역변수로 선언해서 값을 변경해도 가능하다.
클래스 안에서 변수만 그런것같다는 느낌이든다.
static 함수의 호출 클래스 안에서 static같은경우 불러 올수 있다.
간단하다 일반적으로 함수는 클래스안에 생성되어있다. 그리고 사용하는곳이 클래스 밖이기 때문에
::(스코프)연산을 통해서 바로 불러서 사용할수 있다.
이어서 static함수 안에서 객체 주소를 알수 있는 this를 출력할경우 어떻게 될까?
그건 바로 ~!! 멍청한 바보짓~
static함수..변수등의 특징은 기본적으로 클래스 에서 객체가 생성되기전에 마치 전역변수처럼 이미 메모리 떡하니 공간을 잡고 있다. 그런데... 그래서 객체를 생성하지 않아도.. 마음대로 불러서 사용할수 있다. 그렇게 불러올수있는 static에 객체의 주소를 알려고하면... 이건 뭐... 물에 빠진넘 구해주고 돈달라고 하는것과 같다 그래서 static은 기본적으로 객체생성과는 무관하기에 객체의 주소도 알수가 없다.
============================================================================================
#include<iostream>
using namespace std;
//const 멤버 함수
//특징을 잘 살펴볼 것
class Who
{
public:
int i;
Who()
{
i=9;
}
void test(int a) const
{
cout<<"test...\n";
//i=10; // const 함수 속성 위반.. 컴파일불가 기본적으로 const는 상수랑 비숫하다.
// 그래서 함수에 const를 붙일경우 안에 속성인 변수의값을 변경할수 없다.
a=11; //인자같은경우는 변경이 가능하다
cout<<"i="<<i<<endl;
cout<<"a="<<a<<endl;
cout<<this<<endl; //this통해서 생성되는 객체 주소를 알수 있다.
}
static void testStatic() //static은 객체 생성없이 사용가능하다.
{
cout<<"testStatic\n";
//cout<<this<endl; static에서 객체는 생성되기전에 생성되므로 this로 객체 주소값을 알수가없다.
}
};
int main()
{
/*Who obj1;
obj1.test(10); //하지만 함수의 인자로 넘겨받은 값인경우는 대입이 가능하다.
obj1.testStatic();
cout<<&obj1<<endl; //this와 obj1의 주소가 같다.
*/
//testStatic()함수 호출하기
Who::testStatic(); //static함수같은경우 객체 생성없이 상요이 가능하다 그래서 사용하기 위해서
//위치를 주지시켜줘야하는데 그게 바로 스코프 연산이다.
return 0;
}
==========================================================================================
==========================================================================================
shape 클래스가 기본적으로 부모클래스이다 밑으로
rectangle 클래스와 circle 클래스가 자식클래스 받아 있다.
그리고 여기서 virtual(객채기반) 에 대해서 알아보자.. 몇일전에 기본적으로 배웠던 class라는 객체지향에 장점이 바로 부모클래스가 생성된 포인터는 자식포인터를 어디든 출력할수가 있다. 그래서
나온 코드가
shape 클래스로 포인터를 두개를 생성하였고 그 생성된 포인터에 각각 circlr과 rectangle 클래스의 주소를 넣었다.
그리고 출력으로 draw()했다.
간단하게 생각해보면 아 주소를 넣어서 출력 되는겅슨 circlr과 rectangle이겠구나 싶겠지만 잇아하게 출력 화면 약간 다르다.
출력화면
그래서 우리가 원하는 값을 위해서 부모 클래스안에다가 출력하려고 하는 draw()함수 앞에다가 virtual이라고 써버리면 된다. 그러면 바로 circle과 rectangle의 draw()함수를 호출할수가 있다.
virtual의 다른 모습을 보자 위에는 일반적으로 주소를 넣고 동적할당으로 받아서 받아서 생성 해보았다.
그리고 각 클래스 안에다가 소멸자를 만들었다.
대충
cout<<"shape 소멸자\n";
cout<<"rectangle 소멸자\n";
cout<<"cirlce 소멸자";
다음과 같은 코드에서 virtual에 의한 활동을 보자
이런경우 원래 draw()할경우 당연히 rectangle과 circle대한 소멸자도 나와야한다. 하지만
virtual로 함수를 객체기반을 하게 되면... 그 결과값은
자연스레 무시해버린다. 그래서 그냥 동적할당 후 delete가 될때shape만 소멸자로 나왔다.
여기서 그렇다면 당연히 소멸자로rectangle과 circle 이 나와야한다 어떻게 해야할까?
함수도 부모클래스의함수 객체기반을 했다. virtual~ 그러면 우리가 사용하는 부모 클래스의 소멸자도 virtual로 해버리면 간단하다.
이전까지 문법상으로 virtual대한내용을 알고 있었다하지만 소멸자에도 생성하는 경우를 본적이 없기 때문에 사용하지 못한것이다 그냥 그래서 사용하게 된다.
다음은 결과값
-동적바인딩-
어떻게 보면 주소체계에서 보면 간단하게 알수 있다. 기본적으로 객체를 포인터에 주소를 넣을 경우 그 포인터는 객체의 주소를 이미 메모리 가지고 계속 메모리에서 뽑아 사용한다. 이럴경우 정정바인딩이라고 하고 정적개념이 그래서 프로그램을 개발하고난후 실행파일을 생성후 그 기계어를 보고 역으로 어셈블리코드를 만들수가 있다 이같은경우는 객체에 나온 주소를 통해서 역으로 추적하는것이다 이는 메모리에 주소가 그대로 뽑아 쓰기때문이다.
하지만 그와 반대로 동적할당하고 비슷한 동적 바인딩이다 우리가 위에 코드에서 보면 부모클래스 포인터로 해서 각 클래스 크기 만큼 동적할당을 하였다 그러면 이미 그 포인터는 어디의 주소를 가져 올까? 메모리에 그 주소가 있을까? .. 아니 없다. 이것 바로 동적할당으로 받으려는 주소는 아직 메모리에 생성되지 않았다.. 단지 메모리에 공간이 있는지 없는지만 확인했다.
그러면 언제 주소를 알수 있을까? 이는 바로 실행될때이다.
부모클래스 포인터로 cpShape1->draw(); 실행이 된다. 그러면 이 주소는 어떻게 알수 있을까? 만약에 virtual을 하지 않을경우는 당연히 class shape이다 하지만 virtual을 할경우 단지circle인지 retangle인지 모른다. 소멸자에도 마찬가지로 virtual로 해버리면 이게 잘모른다. 실행되는것을 보고 아 이게 circle이구 rectangle이구나를 알수 있다.
적다 보니깐 긴 글인데 아주 간단하게 하면 동적할당과 virtual을 통해서 객체의 주소는 메모리가 에서가져오는것이 아니고 실행될때 그 주소가 바뀌어버린다.
동적바인딩의 장점은 바로보안과 관련이 있다.
자 다음은
class triangle:public shape
{
public:
~triangle()
{
cout<<"triangle 소멸자\n";
}
};
새로운 상속받은 클래스를 만들고
draw()함수를 만들지 않았다.
그리고 포인터로
cpShape1=new triangle;
cpShape1->draw();
delete cpShape1;
draw를 출력하라고 했다.
오잉 shape::draw()출력되었다.
tiangle이 없으니깐 부모클래스의 draw가 출력되었다.
이경우 만약에 부모클래스에 draw를 자식클래스에서 에 강제로 무저껀
생성하게 하는방법이 있다 이를 순수가상함수라고 한다.
virtual void draw()=0 이경우 함수에 마지막에 =0을 넣어 버린다.
어떻게 이게 들어갈까 생각해봤지만... 이경우
자식클래스에 draw()함수를 생성을 안할경우
대충 에러2개 워닝2개 뜬다. 그냥 말그대로draw가 triangle에 없다고 막 이야기한다.
자 그래서 triangle 클래스에 draw을 생성했다.
그결과 너무 너무 잘된다..
================================================================
================================================================
#include<iostream>
using namespace std;
class shape
{
protected:
shape(){}
public:
virtual void draw()=0; //이것은 반드시 만들어야한다. 순수가상함수선언
/* {
cout<<"shape::draw()\n";
}
*/
virtual ~shape()
{
cout<<"shape 소멸자\n";
}
};
class rectangle:public shape
{
public:
void draw()
{
cout<<"rectangle::draw()\n";
}
~rectangle()
{
cout<<"rectangle 소멸자\n";
}
};
class circle:public shape
{
public:
void draw()
{
cout<<"circle::draw()\n";
}
~circle()
{
cout<<"circle 소멸자\n";
}
};
class triangle:public shape
{
public:
void draw()
{
cout<<"triangle::draw()\n";
}
~triangle()
{
cout<<"triangle 소멸자\n";
}
};
int main()
{
// circle ObjCircle;
// rectangle ObjRect;
shape *cpShape1=new circle;
shape *cpShape2=new rectangle;
cpShape1->draw();
cpShape2->draw();
delete cpShape1;
delete cpShape2;
//delete cpcircle;
cpShape1=new triangle;
cpShape1->draw();
delete cpShape1;
return 0;
}
=====================================================================
API 체크박스
라디오박스
BS_RADIOBUTTON
BS_AUTORADIOBUTTON
BS_GROUPBOX
WS_GROUP
#include "MsgProc.h"
enum{ID_R1=11,ID_R2,ID_R3,ID_R4,ID_R5,ID_R6};
static HWND r1,r2,r3,r4,r5,r6;
static int Graph;
static bool bEllipse=FALSE;
LRESULT OnCreate(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
CreateWindow(TEXT("button"),TEXT("Graph"),WS_CHILD | WS_VISIBLE|
BS_GROUPBOX,5,5,120,110,hWnd,(HMENU)0,g_hInst,NULL);
CreateWindow(TEXT("button"),TEXT("카호"),WS_CHILD | WS_VISIBLE|
BS_GROUPBOX,145,5,120,110,hWnd,(HMENU)1,g_hInst,NULL);
r1=CreateWindow(TEXT("button"),TEXT("카호1번째"),WS_CHILD | WS_VISIBLE |WS_GROUP
| BS_AUTORADIOBUTTON,10,20,100,30,hWnd,(HMENU)ID_R1,g_hInst,NULL);
r2=CreateWindow(TEXT("button"),TEXT("카호2번째"),WS_CHILD | WS_VISIBLE|
BS_AUTORADIOBUTTON,10,50,100,30,hWnd,(HMENU)ID_R2,g_hInst,NULL);
r3=CreateWindow(TEXT("button"),TEXT("카호3번째"),WS_CHILD | WS_VISIBLE|
BS_AUTORADIOBUTTON,10,80,100,30,hWnd,(HMENU)ID_R3,g_hInst,NULL);
r4=CreateWindow(TEXT("button"),TEXT("카호1"),WS_CHILD | WS_VISIBLE|WS_GROUP
| BS_AUTORADIOBUTTON,150,20,100,30,hWnd,(HMENU)ID_R4,g_hInst,NULL);
r5=CreateWindow(TEXT("button"),TEXT("카호2"),WS_CHILD | WS_VISIBLE|
BS_AUTORADIOBUTTON,150,50,100,30,hWnd,(HMENU)ID_R5,g_hInst,NULL);
r6=CreateWindow(TEXT("button"),TEXT("카호3"),WS_CHILD | WS_VISIBLE|
BS_AUTORADIOBUTTON,150,80,100,30,hWnd,(HMENU)ID_R6,g_hInst,NULL);
CheckRadioButton(hWnd,ID_R1,ID_R3,ID_R2);
CheckRadioButton(hWnd,ID_R4,ID_R6,ID_R5);
SendMessage(hWnd,WM_COMMAND,(WPARAM)ID_R2,0);
return 0;
}
LRESULT OnCommand(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
switch(LOWORD(wParam))
{
case ID_R1:
Graph=0;
break;
case ID_R2:
Graph=1;
break;
case ID_R3:
Graph=2;
break;
case ID_R4:
Graph=3;
break;
case ID_R5:
Graph=4;
break;
case ID_R6:
Graph=5;
break;
}
InvalidateRect(hWnd,NULL,TRUE);
return 0;
}
LRESULT OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
return 0;
}
LRESULT OnPaint(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
HDC hdc,MemDC;
PAINTSTRUCT ps;
HBITMAP MyBitmap,OldBitmap;
HBRUSH MyBrush,OldBrush;
hdc=BeginPaint(hWnd,&ps);
MemDC =CreateCompatibleDC(hdc);
//MyBrush=CreateSolidBrush(Color);
//OldBrush=(HBRUSH)SelectObject(hdc,MyBrush);
switch(Graph)
{
case 0:
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_BITMAP1));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
break;
case 1:
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(102));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
break;
case 2:
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(103));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
break;
case 3:
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(104));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
break;
case 4:
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(105));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
break;
case 5:
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(106));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
break;
}
SelectObject(MemDC,OldBitmap);
DeleteObject(MyBitmap);
DeleteDC(MemDC);
//SelectObject(hdc,OldBrush);
//DeleteObject(MyBrush);
EndPaint(hWnd,&ps);
return 0;
}
LRESULT OnDestroy(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
PostQuitMessage(0);
return 0;
}
=======
에디트 박스
#include "MsgProc.h"
#define ID_EDIT 100
static TCHAR *Mes=TEXT("왼쪽클릭:에디트 이동,오른쪽클릭:보임/숨김");
static HWND hEdit;
static int nTop=10;
static bool bShow=TRUE;
LRESULT OnCreate(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
hEdit=CreateWindow(TEXT("edit"),NULL,WS_CHILD|WS_VISIBLE|WS_BORDER
|ES_AUTOHSCROLL,10,nTop,200,25,hWnd,(HMENU)ID_EDIT,g_hInst,NULL);
return 0;
}
LRESULT OnCommand(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
return 0;
}
LRESULT OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
nTop+=10;
MoveWindow(hEdit,10,nTop,200,25,TRUE);
return 0;
}
LRESULT OnRButtonDown(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
if(bShow)
{
bShow=FALSE;
ShowWindow(hEdit,SW_HIDE);
}
else
{
bShow=TRUE;
ShowWindow(hEdit,SW_SHOW);
}
return 0;
}
LRESULT OnPaint(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
HDC hdc;
PAINTSTRUCT ps;
hdc=BeginPaint(hWnd,&ps);
TextOut(hdc,200,100,Mes,lstrlen(Mes));
EndPaint(hWnd,&ps);
return 0;
}
LRESULT OnDestroy(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
PostQuitMessage(0);
return 0;
}
======================================
리스트박스
#include "MsgProc.h"
#define ID_LISTBOX 100
TCHAR *Items[]=
{
TEXT("Apple"),
TEXT("Orange"),
TEXT("Melon"),
TEXT("Grape"),
TEXT("Strawberry")
};
HWND hList;
int i;
TCHAR str[128];
LRESULT OnCreate(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
hList=CreateWindow(TEXT("listbox"),NULL,WS_CHILD|WS_VISIBLE|WS_BORDER|
LBS_NOTIFY,10,10,100,200,hWnd,(HMENU)ID_LISTBOX,g_hInst,NULL);
for(i=0;5>i;++i)
{
SendMessage(hList,LB_ADDSTRING,0,(LPARAM)Items[i]);
}
return 0;
}
LRESULT OnCommand(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
switch(LOWORD(wParam)) //컨트롤ID에 따라 분기
{
case ID_LISTBOX:
switch(HIWORD(wParam)) //통지메시지에 따라분기
{
case LBN_SELCHANGE://사용자에 의해 선택 변경(listbox->부모)
i=SendMessage(hList,LB_GETCURSEL,0,0);
SendMessage(hList,LB_GETTEXT,i,(LPARAM)str);
SetWindowText(hWnd,str);
break;
}
}
return 0;
}
LRESULT OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
return 0;
}
LRESULT OnPaint(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
HDC hdc,MemDC;
PAINTSTRUCT ps;
HBITMAP MyBitmap,OldBitmap;
hdc=BeginPaint(hWnd,&ps);
MemDC =CreateCompatibleDC(hdc);
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(105));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
SelectObject(MemDC,OldBitmap);
DeleteObject(MyBitmap);
DeleteDC(MemDC);
EndPaint(hWnd,&ps);
return 0;
}
LRESULT OnDestroy(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
PostQuitMessage(0);
return 0;
}
=====================================
#include "MsgProc.h"
#define ID_COMBOBOX 100
TCHAR *Items[]=
{
TEXT("Apple"),
TEXT("Orange"),
TEXT("Melon"),
TEXT("Grape"),
TEXT("Strawberry")
};
HWND hCombo;
int i;
TCHAR str[128];
LRESULT OnCreate(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
hCombo=CreateWindow(TEXT("Combobox"),NULL,WS_CHILD|WS_VISIBLE|CBS_DROPDOWN
,10,10,100,200,hWnd,(HMENU)ID_COMBOBOX,g_hInst,NULL);
for(i=0;5>i;++i)
{
SendMessage(hCombo,CB_ADDSTRING,0,(LPARAM)Items[i]);
}
return 0;
}
LRESULT OnCommand(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
switch(LOWORD(wParam)) //컨트롤ID에 따라 분기
{
case ID_COMBOBOX:
switch(HIWORD(wParam)) //통지메시지에 따라분기
{
case CBN_SELCHANGE://사용자에 의해 선택 변경(listbox->부모)
i=SendMessage(hCombo,CB_GETCURSEL,0,0);
SendMessage(hCombo,CB_GETLBTEXT,i,(LPARAM)str);
SetWindowText(hWnd,str);
break;
case CBN_EDITCHANGE:
GetWindowText(hCombo,str,128);
SetWindowText(hWnd,str);
break;
}
}
return 0;
}
LRESULT OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
return 0;
}
LRESULT OnPaint(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
HDC hdc,MemDC;
PAINTSTRUCT ps;
HBITMAP MyBitmap,OldBitmap;
hdc=BeginPaint(hWnd,&ps);
MemDC =CreateCompatibleDC(hdc);
MyBitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(105));
OldBitmap = (HBITMAP)SelectObject(MemDC,MyBitmap);
BitBlt(hdc,300,0,500,300,MemDC,0,0,SRCCOPY);
SelectObject(MemDC,OldBitmap);
DeleteObject(MyBitmap);
DeleteDC(MemDC);
EndPaint(hWnd,&ps);
return 0;
}
LRESULT OnDestroy(HWND hWnd, WPARAM wParam, LPARAM IParam)
{
PostQuitMessage(0);
return 0;
}