C++ 생성자, 소멸자, 상속
내장형 하드웨어/C++ / 2011. 11. 11. 14:41
- 복습
→ 전역변수와 이름이 겹칠 때 ::를 사용하면 전역을 뜻한다.
※ 잠시 JAVA의 main()을 생각해 보면 자바는 매인함수가 클래스 안에 있다.
class ~~~~
{
public static void main()
}
→ 즉, 객체안에 있는 함수이다.
→ 프로그램은 진입점(엔트리 포인트)을 항상 생각해야 한다.
→ C, C++등은 main()이며, WINAPI는 WinMain()이 엔트리 포인트
→ 자바는 main()이 클래스 안에 있으므로 객체가 생성되지 않으면 main을 호출할 수 없다. 따라서 static이 앞에 붙어 있다.(static은 정적이므로 컴파일 단계에서 main()을 생성하게 한다.)
→ JAVA Test
→ 위의 예제에서 헤더파일 include에 전처리 기법을 보면
→ OBJ.test(); // 객체 기반 호출(객체가 있을 때만 가능)
emb::test(); // static 기반 호출(static 함수이므로 가능)
- 자동차 클래스 작성 예제
→ 우선 생성자와 소멸자는 반환형이 없으며, 이는 특수하다.
→ 객체를 생성할 때 만들어 지며 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
→ 살펴보면 객채가 1, 2, 3, 4, 5의 순서로 생성되고 5, 4, 3, 2, 1의 순서로 소멸됨이 보인다.
- 상속을 이용한 자동차 클래스 제작 예제
→ 전역변수와 이름이 겹칠 때 ::를 사용하면 전역을 뜻한다.
※ 잠시 JAVA의 main()을 생각해 보면 자바는 매인함수가 클래스 안에 있다.
class ~~~~
{
public static void main()
}
→ 즉, 객체안에 있는 함수이다.
→ 프로그램은 진입점(엔트리 포인트)을 항상 생각해야 한다.
→ C, C++등은 main()이며, WINAPI는 WinMain()이 엔트리 포인트
→ 자바는 main()이 클래스 안에 있으므로 객체가 생성되지 않으면 main을 호출할 수 없다. 따라서 static이 앞에 붙어 있다.(static은 정적이므로 컴파일 단계에서 main()을 생성하게 한다.)
→ JAVA Test
class test
{
static int A; // test의 멤버
public static void main(String[] args) // static으로 실행전에 main() 생성
{
A = 100; // A가 static이 붙지 않았으므로 에러.
System.out.println("Hello");
System.out.println("A");
emb.test(); // 현재 디렉토리 내에 emb 클래스가 있는지 찾는다.
//kkk.test(); // kkk의 클래스가 없으므로 에러
}
}
class emb
{
public static void test()
{
System.out.println("Test Method");
}
}
→ JAVA Test{
static int A; // test의 멤버
public static void main(String[] args) // static으로 실행전에 main() 생성
{
A = 100; // A가 static이 붙지 않았으므로 에러.
System.out.println("Hello");
System.out.println("A");
emb.test(); // 현재 디렉토리 내에 emb 클래스가 있는지 찾는다.
//kkk.test(); // kkk의 클래스가 없으므로 에러
}
}
class emb
{
public static void test()
{
System.out.println("Test Method");
}
}
※ 윈도우에서 java 가상머신은 기본으로 깔려있고 컴파일러는 설치해야 한다.
→ 자바는 클래스 단위로 컴파일(C로 치면 object). 즉, 객체 단위로 컴파일 한다.
→ 따라서 위와 같이 컴파일 하면 class 파일이 test와 emp 두개가 생성되는 것을 확인할 수 있다.
→ C++로 돌아가서
#if 1
#include<iostream.h>
#else
#include<stdio.h>
#endif
class emb
{
//static int A;
public :
static void test()
{
//A = 100;
//cout << A << endl;
cout << "test" << endl;
return ;
}
};
int main()
{
//emb OBJ;
//OBJ.test(); // 객체 기반 호출(객체가 있을 때만 가능)
emb::test(); // static 기반 호출(static 함수이므로 가능)
return 0;
}
#include<iostream.h>
#else
#include<stdio.h>
#endif
class emb
{
//static int A;
public :
static void test()
{
//A = 100;
//cout << A << endl;
cout << "test" << endl;
return ;
}
};
int main()
{
//emb OBJ;
//OBJ.test(); // 객체 기반 호출(객체가 있을 때만 가능)
emb::test(); // static 기반 호출(static 함수이므로 가능)
return 0;
}
→ 위의 예제에서 헤더파일 include에 전처리 기법을 보면
#if 1
#include<iostream.h>
#else
#include<stdio.h>
#endif
→ if 문을 0으로 하면 else 문으로 실행되고 1로 하면 if의 헤더가 적용된다.#include<iostream.h>
#else
#include<stdio.h>
#endif
→ OBJ.test(); // 객체 기반 호출(객체가 있을 때만 가능)
emb::test(); // static 기반 호출(static 함수이므로 가능)
- 자동차 클래스 작성 예제
#if 1
#include<iostream.h>
#else
#include<stdio.h>
#endif
// 자동차 클래스
class car
{
private:
unsigned int uiNumber;
public:
// 생성자 - 자동 호출 된다.(반환형이 없는 특수한 경우)
// 객체를 생성할 때 만들어 진다.
// 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
car() // 인자가 없는 생성자를 디폴트 생성자라 한다.
{
cout << "Car class 생성자 호출" << endl;
}
car(unsigned int uiNumber) // 자동차 일련번호
{
(*this).uiNumber = uiNumber;
cout << this->uiNumber << "Car class 생성자 호출" << endl;
}
~car() // 소멸자 - 앞에 틸드(~)를 붙인다. main함수가 종료되기 전에 호출된다.
{
cout << "CAR class 소멸자 호출" << endl;
}
};
int main()
{
cout << "---------------------" <<endl;
cout << "1" <<endl;
car OBJ1;
car OBJ2;
car OBJ3;
cout << "2" <<endl;
car OBJ4;
car OBJ5;
cout << "3" <<endl;
cout << "---------------------" <<endl;
return 0;
}
→ 생성자와 소멸자를 살펴보면#include<iostream.h>
#else
#include<stdio.h>
#endif
// 자동차 클래스
class car
{
private:
unsigned int uiNumber;
public:
// 생성자 - 자동 호출 된다.(반환형이 없는 특수한 경우)
// 객체를 생성할 때 만들어 진다.
// 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
car() // 인자가 없는 생성자를 디폴트 생성자라 한다.
{
cout << "Car class 생성자 호출" << endl;
}
car(unsigned int uiNumber) // 자동차 일련번호
{
(*this).uiNumber = uiNumber;
cout << this->uiNumber << "Car class 생성자 호출" << endl;
}
~car() // 소멸자 - 앞에 틸드(~)를 붙인다. main함수가 종료되기 전에 호출된다.
{
cout << "CAR class 소멸자 호출" << endl;
}
};
int main()
{
cout << "---------------------" <<endl;
cout << "1" <<endl;
car OBJ1;
car OBJ2;
car OBJ3;
cout << "2" <<endl;
car OBJ4;
car OBJ5;
cout << "3" <<endl;
cout << "---------------------" <<endl;
return 0;
}
→ 우선 생성자와 소멸자는 반환형이 없으며, 이는 특수하다.
→ 객체를 생성할 때 만들어 지며 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
→ 인자가 없는 생성자를 디폴트 생성자라 한다. |
#if 1
#include<iostream.h>
#include<stdlib.h>
#else
#include<stdio.h>
#endif
void test();
// 자동차 클래스
class car
{
friend void test();
private:
unsigned int uiNumber; // 자동차 일련 번호
unsigned char* ucpVendor; // 제조사
// 생성자 - 자동 호출 된다.(반환형이 없는 특수한 경우)
// 객체를 생성할 때 만들어 진다.
// 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
car() // 인자가 없는 생성자를 디폴트 생성자라 한다.
{
uiNumber = 0;
ucpVendor = 0;
cout << "Car class 생성자 호출" << endl;
}
public:
car(unsigned int uiNumber) // 자동차 일련번호
{
ucpVendor = 0;
(*this).uiNumber = uiNumber;
cout << this->uiNumber << " Car class 생성자 호출" << endl;
}
car(unsigned int uiNumber, char *cpVendor) // 제조사
{
unsigned int uiLen; // 길이를 받기 위해
uiLen = strlen(cpVendor);
ucpVendor = (unsigned char*)malloc(uiLen+1); // NULL을 위해 +1
strcpy((char *)ucpVendor,cpVendor);
(*this).uiNumber = uiNumber;
cout << this->uiNumber << cpVendor<< " Car class 생성자 호출" << endl;
}
~car() // 소멸자 - 앞에 틸드(~)를 붙인다. main함수가 종료되기 전에 호출된다.
{
if(0 != ucpVendor)
{
free(ucpVendor);
}
cout << uiNumber << " CAR class 소멸자 호출" << endl;
}
};
int main()
{
cout << "---------------------" <<endl;
car OBJ1(1, "KIA");
car OBJ2=2;
car OBJ3=3;
car OBJ4=4;
car OBJ5=5;
cout << "---------------------" <<endl;
// car OBJ6; // 디폴트 생성자를 private로 만들었기 때문에
// 생성되지 않는다.(기법으로 사용 가능)
// 소멸자에는 절대 pivate를 쓰지않는다.
return 0;
}
void test()
{
car OBJ6;
}
→ 결과#include<iostream.h>
#include<stdlib.h>
#else
#include<stdio.h>
#endif
void test();
// 자동차 클래스
class car
{
friend void test();
private:
unsigned int uiNumber; // 자동차 일련 번호
unsigned char* ucpVendor; // 제조사
// 생성자 - 자동 호출 된다.(반환형이 없는 특수한 경우)
// 객체를 생성할 때 만들어 진다.
// 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
car() // 인자가 없는 생성자를 디폴트 생성자라 한다.
{
uiNumber = 0;
ucpVendor = 0;
cout << "Car class 생성자 호출" << endl;
}
public:
car(unsigned int uiNumber) // 자동차 일련번호
{
ucpVendor = 0;
(*this).uiNumber = uiNumber;
cout << this->uiNumber << " Car class 생성자 호출" << endl;
}
car(unsigned int uiNumber, char *cpVendor) // 제조사
{
unsigned int uiLen; // 길이를 받기 위해
uiLen = strlen(cpVendor);
ucpVendor = (unsigned char*)malloc(uiLen+1); // NULL을 위해 +1
strcpy((char *)ucpVendor,cpVendor);
(*this).uiNumber = uiNumber;
cout << this->uiNumber << cpVendor<< " Car class 생성자 호출" << endl;
}
~car() // 소멸자 - 앞에 틸드(~)를 붙인다. main함수가 종료되기 전에 호출된다.
{
if(0 != ucpVendor)
{
free(ucpVendor);
}
cout << uiNumber << " CAR class 소멸자 호출" << endl;
}
};
int main()
{
cout << "---------------------" <<endl;
car OBJ1(1, "KIA");
car OBJ2=2;
car OBJ3=3;
car OBJ4=4;
car OBJ5=5;
cout << "---------------------" <<endl;
// car OBJ6; // 디폴트 생성자를 private로 만들었기 때문에
// 생성되지 않는다.(기법으로 사용 가능)
// 소멸자에는 절대 pivate를 쓰지않는다.
return 0;
}
void test()
{
car OBJ6;
}
→ 살펴보면 객채가 1, 2, 3, 4, 5의 순서로 생성되고 5, 4, 3, 2, 1의 순서로 소멸됨이 보인다.
→ 생성자가 private면 객체를 생성하지 못한다.(기법으로 사용할 수 있다.→ 의도적으로 접근 생성자를 이용)
→ 전역변수의 사용(friend 사용법)
friend void test()
→ 클래스 안에 friend로 함수를 선언하여(friend void test()) test()가 OBJ 생성이 가능하게 한다.
→ friend의 사용은 위험할 수 있다. 은닉을 해제하는 것이므로 main() 등에는 절대 쓰면 안된다.
※ encapsulation(데이터의 은닉 - private)
※ overloading(다양성)
- 상속
→ 형식
// JAVA class A { }; C extends A { }; |
// C++ class A { }; class C:A { }; |
- 상속을 이용한 자동차 클래스 제작 예제
#if 1
#include<iostream.h>
#include<stdlib.h>
#else
#include<stdio.h>
#endif
void test();
// 자동차 클래스
class car
{
// 상속 받은 클래스만 사용할 수 있다.
protected:
unsigned int uiSpeed;
// 클래스 내에서만 사용할 수 있다.
private:
unsigned int uiNumber; // 자동차 일련 번호
unsigned char* ucpVendor; // 제조사
// 생성자 - 자동 호출 된다.(반환형이 없는 특수한 경우)
// 객체를 생성할 때 만들어 진다.
// 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
car() // 인자가 없는 생성자를 디폴트 생성자라 한다.
{
uiNumber = 0;
ucpVendor = 0;
cout << "Car class 생성자 호출" << endl;
}
// 전체가 사용할 수 있다.
public:
car(unsigned int uiNumber) // 자동차 일련번호
{
ucpVendor = 0;
(*this).uiNumber = uiNumber;
cout << this->uiNumber << " Car class 생성자 호출" << endl;
}
car(unsigned int uiNumber, char *cpVendor) // 제조사
{
unsigned int uiLen; // 길이를 받기 위해
uiLen = strlen(cpVendor);
ucpVendor = (unsigned char*)malloc(uiLen+1); // NULL을 위해 +1
strcpy((char *)ucpVendor,cpVendor);
(*this).uiNumber = uiNumber;
cout << this->uiNumber << cpVendor<< " Car class 생성자 호출" << endl;
}
~car() // 소멸자 - 앞에 틸드(~)를 붙인다. main함수가 종료되기 전에 호출된다.
{
if(0 != ucpVendor)
{
free(ucpVendor);
}
cout << uiNumber << " CAR class 소멸자 호출" << endl;
}
};
class K5:car // car 클래스의 public을 상속 받는다..
{
public:
K5() // 생성자
:car(1234, "KIA")
{
cout << "(생성자)K5가 생성되었습니다." << endl;
uiSpeed = 0;
//uiNumber = 7; // private이므로 에러
}
~K5(void) // 소멸자
{
cout << "(소멸자)K5가 생성되었습니다." << endl;
}
void speedUp(void)
{
uiSpeed = uiSpeed+10;
if(100<uiSpeed)
{
uiSpeed = 100;
}
cout << "지금 속도는 " << uiSpeed << "Km입니다." << endl;
return ;
}
void speedDown(void)
{
if(0==uiSpeed)
{
uiSpeed = 0;
}
else
{
uiSpeed = uiSpeed-10;
}
cout << "지금 속도는 " << uiSpeed << "Km입니다." << endl;
}
};
int main()
{
unsigned char ucVal;
K5 OBJ;
car OBJ2(5678, "싸제 자동차");
// OBJ2.uiSpeed = 100;// protected라 상속 클래스에서만 사용 가능
while('q' != ucVal)
{
cout << "명령을 입력하시오" << endl;
cin >> ucVal;
if('u' == ucVal)
{
OBJ.speedUp();
}
if('i' == ucVal)
{
OBJ.speedDown();
}
}
return 0;
}
#include<iostream.h>
#include<stdlib.h>
#else
#include<stdio.h>
#endif
void test();
// 자동차 클래스
class car
{
// 상속 받은 클래스만 사용할 수 있다.
protected:
unsigned int uiSpeed;
// 클래스 내에서만 사용할 수 있다.
private:
unsigned int uiNumber; // 자동차 일련 번호
unsigned char* ucpVendor; // 제조사
// 생성자 - 자동 호출 된다.(반환형이 없는 특수한 경우)
// 객체를 생성할 때 만들어 진다.
// 생성자는 여러개를 만들 수 있으나 소멸자는 하나만 만들 수 있다.
car() // 인자가 없는 생성자를 디폴트 생성자라 한다.
{
uiNumber = 0;
ucpVendor = 0;
cout << "Car class 생성자 호출" << endl;
}
// 전체가 사용할 수 있다.
public:
car(unsigned int uiNumber) // 자동차 일련번호
{
ucpVendor = 0;
(*this).uiNumber = uiNumber;
cout << this->uiNumber << " Car class 생성자 호출" << endl;
}
car(unsigned int uiNumber, char *cpVendor) // 제조사
{
unsigned int uiLen; // 길이를 받기 위해
uiLen = strlen(cpVendor);
ucpVendor = (unsigned char*)malloc(uiLen+1); // NULL을 위해 +1
strcpy((char *)ucpVendor,cpVendor);
(*this).uiNumber = uiNumber;
cout << this->uiNumber << cpVendor<< " Car class 생성자 호출" << endl;
}
~car() // 소멸자 - 앞에 틸드(~)를 붙인다. main함수가 종료되기 전에 호출된다.
{
if(0 != ucpVendor)
{
free(ucpVendor);
}
cout << uiNumber << " CAR class 소멸자 호출" << endl;
}
};
class K5:car // car 클래스의 public을 상속 받는다..
{
public:
K5() // 생성자
:car(1234, "KIA")
{
cout << "(생성자)K5가 생성되었습니다." << endl;
uiSpeed = 0;
//uiNumber = 7; // private이므로 에러
}
~K5(void) // 소멸자
{
cout << "(소멸자)K5가 생성되었습니다." << endl;
}
void speedUp(void)
{
uiSpeed = uiSpeed+10;
if(100<uiSpeed)
{
uiSpeed = 100;
}
cout << "지금 속도는 " << uiSpeed << "Km입니다." << endl;
return ;
}
void speedDown(void)
{
if(0==uiSpeed)
{
uiSpeed = 0;
}
else
{
uiSpeed = uiSpeed-10;
}
cout << "지금 속도는 " << uiSpeed << "Km입니다." << endl;
}
};
int main()
{
unsigned char ucVal;
K5 OBJ;
car OBJ2(5678, "싸제 자동차");
// OBJ2.uiSpeed = 100;// protected라 상속 클래스에서만 사용 가능
while('q' != ucVal)
{
cout << "명령을 입력하시오" << endl;
cin >> ucVal;
if('u' == ucVal)
{
OBJ.speedUp();
}
if('i' == ucVal)
{
OBJ.speedDown();
}
}
return 0;
}
→ main 함수가 운전자(소유주) |
'내장형 하드웨어 > C++' 카테고리의 다른 글
C++ - 객체 소멸 순서, 객체 생성(정적, 동적 할당-malloc, new) (0) | 2011.11.15 |
---|---|
C++ - car class 추가, 다중상속, 유도(derivation), 타입 (0) | 2011.11.14 |
C++ 클래스, 접근속성, scope 연산자(::), inline (0) | 2011.11.10 |
C++ (함수 인자의 새로운 용법, 오버로딩 과정 확인) (0) | 2011.11.09 |
객체지향, C++ 첫시간(cout, endl, 오버로딩) (0) | 2011.11.08 |