Contents
1. ë¬¸ì œ ì œê¸°ë¥¼ ë‹´ì�€ 설명 코드 ¶
- 다ì�Œ 소스ì—�서는 die메소드ì—�서 ìž�ì‹ ì�„ ì‚ì œí•´ì¤�니다. 그런ë�°. ì‚ì œë�˜ê³ ë�„ 뻔뻔스럽게 ìž�ì‹ ì�˜ 메소드를 호출하네요. 어떻게 ë�œê²ƒì�¼ê¹Œìš”? 알아봅시다.
~cpp
#include <iostream>
using namespace std;
class Foo{
public:
int id;
Foo(){
static idSequance = 0;
id = idSequance++;
cout << "Create! id = " << id << endl;
}
void die(){
cout << "I suicide. Id is " << id << endl;
delete this; // ìž�ì‹ ì‚ì œ
}
void sayMyId(){
cout << "My Id is no " << id << endl;
}
void sayHello(){
cout << "say Hello" << endl;
}
};
int main(int argc, char** argv)
{
cout << endl << ":::::: Case 1 - ë�™ì �í• ë‹¹ " << endl;
Foo* foo1 = new Foo();// Create! 를 ì¶œë ¥í•œë‹¤.
foo1->sayHello(); // Hello ì¶œë ¥
foo1->sayMyId(); // id ì¶œë ¥
foo1->die(); // ê°�ì²´ ì‚ì œ
foo1->sayHello(); // �작 가능
foo1->sayMyId(); // �작 가능
// id 확�차
cout << endl << ":::::: Case 2 - id 확�" << endl;
Foo* foo2 = new Foo();// Create! 를 ì¶œë ¥í•œë‹¤.
foo2->sayHello(); // Hello World ì¶œë ¥
foo2->sayMyId(); // id ì¶œë ¥
foo2->die();
foo2->sayHello();
foo2->sayMyId();
cout << endl << ":::::: Case 3 - í�¬ì�¸í„° NULL로 í•˜ê³ ë©”ì†Œë“œ 호출하기 " << endl;
Foo* foo3 = NULL; // �세한 설명보세요.
foo3->sayHello(); // Hello 를 ì¶œë ¥í•œë‹¤.
//foo3->sayMyId(); // debug, release 모ë‘� ë�™ìž‘í• ìˆ˜ 없다.
//foo3->die(); // debug, release 모ë‘� ë�™ìž‘í• ìˆ˜ 없다.
cout << endl << ":::::: Case3 - ì§€ì—변수로 ì„ ì–¸" << endl;
Foo foo4;
foo4.sayHello(); // Hello World ì¶œë ¥
foo4.sayMyId(); // id ì¶œë ¥
foo4.die(); // debug mode�서 assertion error
foo4.sayHello(); // release �서 �작 가능
foo4.sayMyId(); // release �서 �작 가능
cout << endl;
return 0;
}
결과는 다ì�Œê³¼ ê°™ì�´ ì¶œë ¥ë�©ë‹ˆë‹¤. 비êµ�해보면서, ìƒ�ê°�í•´ ë³´ê³ ì�´í•´ê°€ì§€ 않는다면 ìž�세한 설명ì�„ 보세요.~cpp :::::: Case 1 - ë�™ì �í• ë‹¹ Create! id = 0 say Hello My Id is no 0 I suicide. Id is 0 say Hello My Id is no 3604872 :::::: Case 2 - id 확ì�¸ Create! id = 1 say Hello My Id is no 1 I suicide. Id is 1 say Hello My Id is no 3604872 :::::: Case 3 - í�¬ì�¸í„° NULL로 í•˜ê³ ë©”ì†Œë“œ 호출하기 say Hello :::::: Case3 - ì§€ì—변수로 ì„ ì–¸ Create! id = 2 say Hello My Id is no 2 I suicide. Id is 2 say Hello My Id is no 2 Press any key to continue
2.1. Case1 - ë�™ì �í• ë‹¹ ¶
~cpp Foo* foo1 = new Foo(); // Create! 를 ì¶œë ¥í•œë‹¤. foo1->sayHello(); // Hello World ì¶œë ¥ foo1->sayMyId(); // id ì¶œë ¥ foo1->die(); // 죽였다. foo1->sayHello(); // 호출ì�´ ë�œë‹¤? foo1->sayMyId(); // ì�´ê²ƒë�„..--;
2.2. Case2 - í�¬ì�¸í„° NULL로 í•˜ê³ ë©”ì†Œë“œ 호출하기 ¶
~cpp Foo* foo2 = NULL; // ìž�세한 설명보세요. foo2->sayHello(); // Hello 를 ì¶œë ¥í•œë‹¤.(ì�Œ--;) foo2->sayMyId(); // debug, release 모ë‘� ë�™ìž‘í• ìˆ˜ 없다. foo2->die(); // debug, release 모ë‘� ë�™ìž‘í• ìˆ˜ 없다.
2.3. Case3 - ì§€ì—변수로 ì„ ì–¸ ¶
~cpp Foo foo3; foo3.sayHello(); // Hello World ì¶œë ¥ foo3.sayMyId(); // id ì¶œë ¥ foo3.die(); // debug modeì—�서 assertion error foo3.sayHello(); // release ì—�서 ë�™ìž‘ 가능 foo3.sayMyId(); // release ì—�서 ë�™ìž‘ 가능
3. ìž�세한 설명 ¶
위� "간단한 설명=코드"를 �용하면서 설명합니다.
C++ì�˜ 목표는 기존 Cì�˜ 성능ì�„ 해하지 않으면서 OOP를 섞는 것입니다. í•„ì—°ì �으로 OOPì � ì‚¬ê³ ì—�서 용납하기 ì–´ë ¤ìš´ 코드를 ì‹¤í–‰í• ìˆ˜ 있습니다. OOP를 Cì�˜ 구현 위ì—�서 해야 ë�©ë‹ˆë‹¤.
ì�´ ì�´ìƒ�하게 ë³´ì�´ëŠ” 코드를 ì�´í•´í•˜ê¸° 위해서는 C++ì�˜ ì›�ë¡ ì �ì�¸ 배경지ì‹�ì�´ 필요합니다.
- 첫째로, C++� �래스와 �스턴스 �성� 알아봅시다.
- 둘째로, ì�¸ìŠ¤í„´ìŠ¤ì—� ê·€ì†�ë�œ 멤버 함수들ì�„ 실행하는 것ì�„ ìƒ�ê°�í•´ ë³´ê² ìŠµë‹ˆë‹¤.
- 마지막으로, 위ì�˜ ë¬¸ì œì œê¸°ì—� 대해 ë¶„ì„�í•´ 봅시다.
3.1. C++ì—�서 í�´ëž˜ìФì�˜ ì„ ì–¸ê³¼ ì�¸ìŠ¤í„´ìŠ¤ì�˜ ìƒ�성입니다. ¶
ìž�ì‹ ì�´ 컴파ì�¼ëŸ¬ê°€ ë�˜ì—ˆë‹¤ê³ ê°€ì •í•´ 봅시다. 우리가 class를 ì„ ì–¸í•˜ê³ ì»´íŒŒì�¼í•˜ë ¤ë©´ 프로그램ì�˜ ì˜�ì—ì—� class ì�˜ Data 들ì�„ ì €ìž¥í• ìˆ˜ 있는 "class í‹€"ì�˜ ì •ë³´ë¥¼ ë‹´ì•„ 놓ì�„ ê³³ì�´ 필요합니다.
~cpp
class Foo{
public:
int id; // <- ì�´ 부분ì�˜ ì •ë³´ 입니다.
};
C++ì�€ Strong typed language ì�´ë¯€ë¡œ 컴파ì�¼ 시간ì—� ëª¨ë“ í˜•ì�´ ì„ ì–¸ë�˜ê³ , 사용ë�˜ëŠ” 것ì�„ ê²€ì¦�í• ìˆ˜ 있습니다. 하지만 ì�´ëŠ” 다ì�Œê³¼ ê°™ì�€ ì§€ì— ë³€ìˆ˜ì—� êµí•œí•©ë‹ˆë‹¤. ~cpp Foo foo4;new 키워드로 í• ë‹¹ì‹œì—�는 runtime ì—� class ì�˜ instance 를 ì°�ì–´ 낼수 있어야 합니다. ì�´ë¥¼ 위해 프로그램 안ì—�는 위ì�˜ idê°€ int ë�¼ëŠ” ì •ë³´ë¥¼ 담는 classì�˜ "class í‹€" ì •ë³´ë¥¼ 담는 ê³³ì�´ 필요합니다.
여기까지가, class 와 struct 키워드가 하는 ë�™ì�¼í•œ 작업입니다. ê·¸ë¦¬ê³ , class ì—�는 몇가지 ë�” ìƒ�ê°�해야 하는ë�°, 그중 하나가 foo 를 ì�´ìš©í•´ì„œ ì–´ë– í•œ member 함수를 í˜¸ì¶œí• ìˆ˜ 있는가 입니다.
그러나, 컴파ì�¼ëŸ¬ì�¸ 우리는 ì�´ ì •ë³´ë¥¼ ì§€ì— ë³€ìˆ˜ì�´ë“ , new 로 í• ë‹¹ì�´ë“ 컴파ì�¼ 시간ì—� ì�¸ìž�ì�˜ typeì�„ ë³´ê³ í•¨ìˆ˜ 호출 ìœ íš¨ì„±ì�„ 확ì�¸í•˜ê³ , ì �ì ˆí•œ 함수 í�¬ì�¸í„°ë¥¼ 함수 호출하는 부분ì—� 넣어 줄수 있습니다. ê·¸ë¦¬ê³ ì‹¤í–‰í• ìˆ˜ 있는ë�° ì�´ ê³¼ì •ì�„ ë‘�번째ì—�서 설명합니다.
그외 class와 instanceì�˜ ìƒ�성시 vpt와, ìƒ�ì†� 관계ì—� 대한 pointer ì •ë³´ê°€ ë�” 들어 가야 합니다. 그러나 여기ì—�서는 ìƒ�ê°�하지 않습니다. 둘째로 넘어갑니다
3.2. instance ì—� ê·€ì†�ë�œ 멤버 함수들ì�„ 실행해 봅시다. ¶
ìž� 계ì†� 우리는 컴파ì�¼ëŸ¬ 입니다. 컴파ì�¼ëŸ¬ì�¸ 우리는 member 함수 호출 부분ì�„ 함수ì�˜ 실행코드를 가리키는 함수 í�¬ì�¸í„°ë¡œ 모ë‘� êµ�체하였습니다. ê·¸ë¦¬ê³ ì�¸ê°„으로 ë�Œì•„옵시다.
C++ 표준안ì—�서 ì „ì—ì—�서 함수 호출과, instanceì—� ê·€ì†�ë�œ 멤버 함수들ì�˜ 호출ì�„ 가리지 않습니다. 함수 ì„ ì–¸ê³¼ 멤버 함수 ì„ ì–¸ì�˜ 함수 실행 코드는 모ë‘� ë�™ì�¼ 방법으로 ì„ ì–¸ë�˜ê³ , 모ë‘� ë�™ì�¼í•œ 메커니즘ì�˜ 함수 í�¬ì�¸í„°ë¥¼ ì�´ìš©í•´ì„œ 호출합니다.
ì�´ëŸ¬í•œ ì „ì œë�¼ë©´, 한가지 ì�˜ë¬¸ì�´ ìƒ�ê¹�니다.
ì „ì— í•¨ìˆ˜ì™€ ë�™ì�¼í•œ 함수 ì„ ì–¸ì�˜ 형태ë�¼ë©´ ê°�ê°�ì�˜ instanceì—� 어떻게 ì ‘ê·¼í•˜ëŠ”ê°€?
ì „ì— í•¨ìˆ˜ì™€ ë�™ì�¼í•œ 함수 ì„ ì–¸ì�˜ 형태ë�¼ë©´ ê°�ê°�ì�˜ instanceì—� 어떻게 ì ‘ê·¼í•˜ëŠ”ê°€?
무슨 소리� 하면,
그러나
~cpp
class Foo{
public:
int id;
void sayMyId(){
cout << "My Id is no " << id << endl;
}
};
ë�¼ëŠ” 함수는 ê°� instanceì�˜ id ë�¼ëŠ” ì�¸ìž�ì—� ì ‘ê·¼í•©ë‹ˆë‹¤. 그러나
~cpp Foo::sayMyId() ê°™ì�€ 아무런 ì�¸ìž� 없는 함수ì�˜ 실행코드가 함수 ì„ ì–¸ ì˜�ì—ì—� 세팅ë�œë‹¤ë©´, id ë�¼ëŠ” ì�¸ìž�ì—� ì ‘ê·¼í• ìˆ˜ 없습니다. C++ ì—�서는 ì�´ëŸ° 한계를 class ì—� ê·€ì†�ë�œ 함수들ì�˜ 처ì�Œ ì�¸ìž�로 해당 class ì�˜ í�¬ì�¸í„°ë¥¼ 묵시ì �으로 ì„ ì–¸í•´ì„œ í•´ê²°í•˜ê³ ìžˆìŠµë‹ˆë‹¤. 즉,
~cpp Foo:sayMyId()ë�¼ëŠ” 함수 실행 코드가 함수 ì˜�ì—ì—� ì„ ì–¸ë� 때 컴파ì�¼ëŸ¬ê°€
~cpp Foo:sayMyId(Foo* x)ë�¼ëŠ” 형태ì�˜ 함수로 ì„ ì–¸í•˜ê³ , ì‹¤í–‰í• ìˆ˜ 있ë�„ë¡� ë§Œë“니다. ê·¸ë¦¬ê³ , 호출한다면
~cpp Foo* 부분� ~cpp foo1->sayMyId(foo1);형태로 함수 ��터를 세팅해서 함수 코드를 실행합니다.
C++� �러한 다소 황당한 수로 C와� 컴파�시 호환성� 지키면서 OOP를 구현합니다.
사족. ì�´ëŸ¬í•œ 사연ì�´ classë‚´ì—�서 static 멤버 함수를 ì„ ì–¸í•˜ê³ instanceì—�서 í˜¸ì¶œí• ë•Œ instance ì�˜ 멤버 변수ì—� ì ‘ê·¼í•˜ì§€ 못하는 ì�´ìœ ê°€ ë�©ë‹ˆë‹¤. static 함수로 ì„ ì–¸ 하면 묵시ì �으로 pointer 를 세팅하지 ì•Šê³ í•¨ìˆ˜ë¥¼ 호출합니다.
ì�´ëŸ° ë°°ê²½ ì§€ì‹�ì�„ 바탕으로 다ì�Œìœ¼ë¡œ 넘어갑니다.3.3. 위ì�˜ ë¬¸ì œì œê¸°ì—� 대해 ë¶„ì„�í•´ 봅시다. ¶
다�과 같� 코드를 실행하면,
~cpp Foo* foo1 = new Foo(); // Create! 를 ì¶œë ¥í•œë‹¤. foo1->sayHello(); // Hello ì¶œë ¥ foo1->sayMyId(); // id ì¶œë ¥ foo1->die(); // ê°�ì²´ ì‚ì œ foo1->sayHello(); // ë�™ìž‘ 가능 foo1->sayMyId(); // ë�™ìž‘ 가능
ì�´ë ‡ê²Œ 나옵니다.(윈ë�„우즈 플랫í�¼ì—�서)
ì�´ë ‡ê²Œ 나옵니다. (C++ 주ì„� ë¹¼ê³ ) 위ì—�서 ë¬¸ì œì‹œ ë�˜ëŠ” 부분ì�€, 후반ì�˜ ë‘�가지
~cpp Create! id = 0 say Hello My Id is no 0 I suicide. Id is 0 say Hello // ê°�ì²´ ì‚ì œ(delete this)후 실행 코드 My Id is no 3604872 // ê°�ì²´ ì‚ì œ(delete this)후 실행 코드
~cpp sayHello() 와 sayMyId() ì�¼ê²�니다. 둘째 설명ì�˜ member 함수를 호출하는 메커니즘ì�„ ì�´í•´í–ˆë‹¤ë©´ ~cpp sayHello() -> sayHello(Foo*) sayMyId() -> sayMyId(Foo*)형태로 호출ë�œë‹¤ëŠ” 것ì�„ ì§�ìž‘í• ìˆ˜ 있ì�„ ê²�니다. 하지만 ë‘� 함수는 다른 ì �ì�´ 있습니다.
sayHello()는 instance variableì—� ì ‘ê·¼í•˜ì§€ 않는다는 것ì�´ê³ ,
~cpp sayMyId() 는 ì ‘ê·¼í•œë‹¤ëŠ” ì �ì�´ì§€ìš”.ë”°ë�¼ì„œ, ì‚ì œí›„ì—� 메모리를 ì²ì†Œ(?) í•´ë²„ë¦¬ê³ ë‚œí›„ 해당 instance 부분ì�„ 실행해 보리니 idê°€ 다ì�Œê³¼ ê°™ì�´ 엉뚱하게 나오지요.
그리ê³
~cpp say Hello ê°�ì²´ ì‚ì œ(delete this)후 실행 코드 My Id is no 3604872 ê°�ì²´ ì‚ì œ(delete this)후 실행 코드instanceì—� 사용ë�˜ì—ˆë�˜ 메모리는, 해당 processì�˜ 가용 메모리로 ë�Œì•„가지, ì ‘ê·¼ 금지 ì˜�ì—으로 세팅ë�˜ì§€ 않습니다. ì�´ 부분ì�€ delete this 시 해당 instance ì˜�ì—ì�˜ ê°’ì�„ 어떻게 "ì²ì†Œ"하ëŠ�ëƒ�ì—� ë”°ë�¼ì„œ, 플랫í�¼ 별로 다르게 나옵니다.
그리ê³
~cpp delete xë�¼ëŠ” 코드는 xì�˜ ê°’ì�„ 변화시키지 않습니다. 변화시킬수 없습니다. ì�´ìœ 는 call by value 로 넘어온 xì�˜ ê°’ì�„ NULL로 변경시켜봤ìž�, ì˜�í–¥ 받지 않는 코드가 경우가 있기 때문ì—�, 변화시킬 필요성ì�´ 없습니다.
만약 구현 컴파ì�¼ëŸ¬ê°€, 메모리를 system으로 ë°˜í™˜í•˜ê³ ì ‘ê·¼ 금지 ì˜�ì—으로 ì„¤ì •í•œë‹¤ë©´, 다ì�Œ ê°•ì œ ì ‘ê·¼ì‹œ access ì—�러가 ë‚˜ê² ì§€ìš”. ì�´ëŸ¬í•œ 비효율ì � 구현 플랫í�¼ ì—†ì�„ ê²�니다.
foo2~3 ì�´ëŸ¬í•œ ë°°ê²½ ì§€ì‹�ì�„ ì�´ìš©í•´ì„œ 결과를 ì�´í•´í• 수 있는 ë³´ì¶© 설명입니다.
ê·¸ 중 foo2는 C++ì—�서 볼수 있는 웃긴 ì˜ˆì œì§€ìš”. (foo3ë�„ 웃기지만)
~cpp Foo* foo2 = NULL; // ìž�세한 설명보세요. foo2->sayHello(); // Hello 를 ì¶œë ¥í•œë‹¤.ì�´ 코드ì�˜ 결과는
~cpp say Hello과 같� 잘 �작합니다. 호출 형태가
~cpp Foo::sayHello(foo2) -> Foo::sayHello(NULL)ì�´ ë�œê²ƒì�´ê³ , sayHello ë‚´ì—�는 pointer ê°’ NULL ì�„ ì�´ìš©í•œ ì ‘ê·¼ì�´ 없으므로 아무런 ì—�러가 ë°œìƒ�하지 않습니다.
OOPì �ì�¸ ì‚¬ê³ ë¡œ ì‹¤í–‰í• instanceê°€ 없으므로 불가능한 코드지만, 잘 실행ë�©ë‹ˆë‹¤. C++ì—�서 함수 실행시 해당 instanceì�˜ 존재 ìœ ë¬´ë¥¼ 검사하지 않습니다. 검사 í• ìˆ˜ë�„ ì—†ê² ì§€ìš”. NULL ì¡°ì°¨ 0 ì�´ë�¼ëŠ” pointer ê°’ì—� 해당하니까요.
4. ì •ë¦¬ ¶
- C++ ì—�서 class ì�˜ 멤버 함수를 í˜¸ì¶œí• ë•Œ 멤버 함수ì�˜ 첫ì�¸ìž�를 해당 class ì�˜ instance pointer 로 묵시ì �으로 ì„ ì–¸ë�˜ê³ 호출ë�œë‹¤.
- 위ì�˜ 호출시ì—� pointer ì�˜ ìœ íš¨ì„±ì�€ 확ì�¸í•˜ì§€ 않는다.
5. ë�§ë¶™ì—¬ Javaì—�서 비슷한 코드를 봅시다. ¶
instance ìœ ë¬´ë¥¼ 검사하는 Java 코드를 봅시다.
(실행시ì �ì—� null ê°’ì�¸ì§€ ê²€ì‚¬í•˜ê³ , 필요시 instance poolì—�서 instance를 pointer를 ì�´ìš©í•´ì„œ ì ‘ê·¼í•˜ëŠ” 것으로 기억합니다. )
~cpp
// Main.java file
class Foo{
public int a;
void sayHello(){
System.out.println("Hello");
}
}
public class Main {
public static void main(String[] args) {
Foo foo= null;
foo.sayHello();
}
}
ì�´ë¥¼ 실행하면, 다ì�Œê³¼ ê°™ì�€ exceptionì�„ ì¶œë ¥í•©ë‹ˆë‹¤. ì�´ëŠ” Java Language Specification 2nd (3rdê°€ ì•„ì§� 안나왔군요.) 와 jvm specificationì�„ ì°¸ê³ í•˜ì„¸ìš”.(실행시ì �ì—� null ê°’ì�¸ì§€ ê²€ì‚¬í•˜ê³ , 필요시 instance poolì—�서 instance를 pointer를 ì�´ìš©í•´ì„œ ì ‘ê·¼í•˜ëŠ” 것으로 기억합니다. )
~cpp java.lang.NullPointerException at Main.main(Main.java:19) Exception in thread "main"
C++ì—�서는 NULL ì�´ 키워드로 존재하지 ì•Šê³ , 0 ì�´ë�¼ê³ 확실히 약ì†�ë�˜ì–´ 있지 않기 때문ì—� 검사ìž�ì²´ê°€ 불가능합니다.그러나 vmìƒ�ì�˜ 언어들ì�€ 그래서 모ë‘� nullì—� 해당하는 키워드가 ì¡´ìž¬í•˜ê³ ê²€ì‚¬ê°€ 가능합니다.









