가상함수
- 어떤 메소드를 실제로 호출하는 객체가 어떤 클래스인지에 따라 구현이 결정되는 메소드를 뜻한다.
class A {
public:
- 어떤 메소드를 실제로 호출하는 객체가 어떤 클래스인지에 따라 구현이 결정되는 메소드를 뜻한다.
class A {
public:
virtual void print() { cout << "A"; }
};
class B : A{
public:
class B : A{
public:
virtual void print() { cout << "B"; }
};
class C : B {
public:
class C : B {
public:
virtual void print(){ cout << "C"; }
};
실행시에 쓰이는 클래스형( new 다음에 오는 클래스형 )에 따라 호출되는 메소드가 결정된다.
A* a = new C();
B* b1 = new B();
B* b2 = new C();
a->print(); // "C"
b1->print(); // "B"
b2->print(); // "C"
* 가상함수의 장점 :
- 1. 실행시에 메소드를 선택할수 있다는 점.
- 2. 추상메소드로 사용되며 다형성을 구현할수 있다는 점.
class Bird{
public:
실행시에 쓰이는 클래스형( new 다음에 오는 클래스형 )에 따라 호출되는 메소드가 결정된다.
A* a = new C();
B* b1 = new B();
B* b2 = new C();
a->print(); // "C"
b1->print(); // "B"
b2->print(); // "C"
* 가상함수의 장점 :
- 1. 실행시에 메소드를 선택할수 있다는 점.
- 2. 추상메소드로 사용되며 다형성을 구현할수 있다는 점.
class Bird{
public:
virtual void fly() = 0;
};
class Bidulgi : Bird {
public:
class Bidulgi : Bird {
public:
virtual void fly(){ cout << "비둘"; }
};
Bird* bird = new Bidulgi();
bird->fly();
* 가상함수의 단점 : 별도의 메모리의 사용, 오버헤드
- virtual 이란 키워드가 한개라도 붙은 클래스의 객체를 선언할경우, 그 클래스만을 위한 vtable( virtual 테이블 ) 이 하나 생긴다.
객체가 만들어질때 객체의 맨 앞 4byte는 virtual 테이블의 포인터가 저장된다.
virtual 함수 호출시마다 테이블을 참조해야 하므로 부하가 있다.
가상소멸자를 사용하는 이유
class A {
public:
~A(){ a = 0; }
int a;
}
class B : public A{
public:
~B(){ b = 0; }
int b;
};
class C : public B{
public:
~C(){ c = 0; }
int c;
};
A* obj = new C();
delete obj;
- 위의 경우 A클래스의 소멸자만 호출된다. B,C 클래스 부분의 데이터는 초기화 되지 않는다!
class A {
virtual ~A(){ }
}
class B : public A{
virtual ~B(){ }
};
class C : public B{
virtual ~C(){ }
};
A* obj = new C();
delete obj;
- 위의 경우 obj 는 먼저 A클래스를 본다. 그래서 봤더니 소멸자가 virtual 이라,
B클래스로 본다-> B클래스도 또 virtual 이라 C 클래스를 본다.
결국 C 소멸자->B 소멸자 -> A 소멸자 순으로 소멸자를 호출한다.
A* 를 가지고 객체를 지울경우 virtual 로 하지 않으면, 정확한 데이터 초기화가 이루어 지지 않아
메모리 누수가 발생할수 있다.
즉 상속을 이용한 경우, 소멸자는 virtual 로 해줘야 한다.
오버로딩
- 한 클래스에 동일한 이름의 함수를 중복 정의하는 것.
- 이름이 같은 함수에 전달인자의 크기가 다르거나, 전달인자 타입이 다른 경우 오버로딩 허용
- 이름과 전달인자 개수, 전달인자의 타입이 모두 같은 경우는 오버로딩 불가
class D{
public:
Bird* bird = new Bidulgi();
bird->fly();
* 가상함수의 단점 : 별도의 메모리의 사용, 오버헤드
- virtual 이란 키워드가 한개라도 붙은 클래스의 객체를 선언할경우, 그 클래스만을 위한 vtable( virtual 테이블 ) 이 하나 생긴다.
객체가 만들어질때 객체의 맨 앞 4byte는 virtual 테이블의 포인터가 저장된다.
virtual 함수 호출시마다 테이블을 참조해야 하므로 부하가 있다.
가상소멸자를 사용하는 이유
class A {
public:
~A(){ a = 0; }
int a;
}
class B : public A{
public:
~B(){ b = 0; }
int b;
};
class C : public B{
public:
~C(){ c = 0; }
int c;
};
A* obj = new C();
delete obj;
- 위의 경우 A클래스의 소멸자만 호출된다. B,C 클래스 부분의 데이터는 초기화 되지 않는다!
class A {
virtual ~A(){ }
}
class B : public A{
virtual ~B(){ }
};
class C : public B{
virtual ~C(){ }
};
A* obj = new C();
delete obj;
- 위의 경우 obj 는 먼저 A클래스를 본다. 그래서 봤더니 소멸자가 virtual 이라,
B클래스로 본다-> B클래스도 또 virtual 이라 C 클래스를 본다.
결국 C 소멸자->B 소멸자 -> A 소멸자 순으로 소멸자를 호출한다.
A* 를 가지고 객체를 지울경우 virtual 로 하지 않으면, 정확한 데이터 초기화가 이루어 지지 않아
메모리 누수가 발생할수 있다.
즉 상속을 이용한 경우, 소멸자는 virtual 로 해줘야 한다.
오버로딩
- 한 클래스에 동일한 이름의 함수를 중복 정의하는 것.
- 이름이 같은 함수에 전달인자의 크기가 다르거나, 전달인자 타입이 다른 경우 오버로딩 허용
- 이름과 전달인자 개수, 전달인자의 타입이 모두 같은 경우는 오버로딩 불가
class D{
public:
void test( int a );
void test( int a, int b ); // 추가 시 error
int test( double a );
int test( int a, int b );
};
오버라이딩
- 상속구조의 부모클래스로 부터 자식클래스가 함수를 재정의 한것
class Bird{
public:
오버라이딩
- 상속구조의 부모클래스로 부터 자식클래스가 함수를 재정의 한것
class Bird{
public:
virtual void swing() = 0;
};
class Bidulgi : Bird {
public:
class Bidulgi : Bird {
public:
virtual void swing(){ cout << "퍽퍽"; }
};
class Doksuri : Bird {
public:
class Doksuri : Bird {
public:
virtual void swing() { cout << "훅훅"; }
}
다형성
- 부모 클래스의 형 포인터를 이용해 하위 객체들을 참조 할 수 있게 해주는 개념.
- 함수 swing() 이름은 같지만 새 객체에 따라 어떻게 날개짓을 하는지 따로 정의하고
Bird* b = new Doksuri;
b->swing(); // "훅훅"
호출할때 swing() 이라는 함수가 가상함수라면, 다형성이라는 개념이 적용된다.
이 개념은 객체의 실제 형에 우리가 크게 신경쓰지 않아도 된다는 장점이 있다.
포함 vs 상속
- 상속을 하는 경우 : is-a 관계가 성립될때
- 포함을 하는 경우 : has 관계
적 클래스와 무기 클래스가 있을때 상속을 하게 되면 "적은 무기이다?" 이상해진다.
적 클래스가 무기를 '가진다' 라고 말하며, 이때 포함관계를 갖는게 명확하다.
상속
- 부모클래스의 함수와 데이터를 제공받는것. 더 특화된 버전의 클래스를 위한 행동을 제공할 수 있게 해준다.
class Shape {
int center; // 중심점
다형성
- 부모 클래스의 형 포인터를 이용해 하위 객체들을 참조 할 수 있게 해주는 개념.
- 함수 swing() 이름은 같지만 새 객체에 따라 어떻게 날개짓을 하는지 따로 정의하고
Bird* b = new Doksuri;
b->swing(); // "훅훅"
호출할때 swing() 이라는 함수가 가상함수라면, 다형성이라는 개념이 적용된다.
이 개념은 객체의 실제 형에 우리가 크게 신경쓰지 않아도 된다는 장점이 있다.
포함 vs 상속
- 상속을 하는 경우 : is-a 관계가 성립될때
- 포함을 하는 경우 : has 관계
적 클래스와 무기 클래스가 있을때 상속을 하게 되면 "적은 무기이다?" 이상해진다.
적 클래스가 무기를 '가진다' 라고 말하며, 이때 포함관계를 갖는게 명확하다.
상속
- 부모클래스의 함수와 데이터를 제공받는것. 더 특화된 버전의 클래스를 위한 행동을 제공할 수 있게 해준다.
class Shape {
int center; // 중심점
}
class Rectangle : public Shape {
int h; // 세로
int w; // 가로
};
class Ellipse : public Shape{
int a; // 긴 반지름
int b; // 짧은 반지름
};
다중상속
- 한 클래스에서 하나 이상의 클래스를 상속할때 이를 다중 상속이라 부름.
다중상속의 문제점 & 해결방안
class A{
protected:
class Rectangle : public Shape {
int h; // 세로
int w; // 가로
};
class Ellipse : public Shape{
int a; // 긴 반지름
int b; // 짧은 반지름
};
다중상속
- 한 클래스에서 하나 이상의 클래스를 상속할때 이를 다중 상속이라 부름.
다중상속의 문제점 & 해결방안
class A{
protected:
bool flag;
};
class B : public A{ };
class C : public A{ };
class D : public B, public C {
public:
void setFlag( bool bflag ){ flag = bflag; }
class B : public A{ };
class C : public A{ };
class D : public B, public C {
public:
void setFlag( bool bflag ){ flag = bflag; }
};
다중상속중에 문제가 발생할수 있는 경우는 일명 다이아몬드 상속의 경우이다.
이렇게 다중상속을 하게 될경우, B와 C클래스에 각각 flag 라는 변수가 생긴다.
flag = bflag; 하게 되면 이때 flag가 B클래스의 것인지, C클래스의 것인지 불분명해져서
컴파일시 오류가 발생하게 된다.
한가지 방법으로는 B::flag = bflag; 이런식으로 해결한다.
위와 같은 상속은 메모리상에 flag 가 2개가 잡히게 되는데
이문제를 해결하기 위해 C++ 은 가상상속이라는 새로운 개념을 도입하였다.
다이아몬드 상속 계층이 만들어지더라도 자식 개체 구조 내에 한번씩만 부모 클래스가 포함되도록 해준다.
프로그래밍의 종류
일반프로그래밍이란 ? STL 을 이용한 제네릭한 프로그램을 구현하는 패러다임을 말한다.
객체지향프로그래밍이란? 클래스를 사용하여 객체 중심적으로 생각하여 프로그램을 구현
다중상속중에 문제가 발생할수 있는 경우는 일명 다이아몬드 상속의 경우이다.
이렇게 다중상속을 하게 될경우, B와 C클래스에 각각 flag 라는 변수가 생긴다.
flag = bflag; 하게 되면 이때 flag가 B클래스의 것인지, C클래스의 것인지 불분명해져서
컴파일시 오류가 발생하게 된다.
한가지 방법으로는 B::flag = bflag; 이런식으로 해결한다.
위와 같은 상속은 메모리상에 flag 가 2개가 잡히게 되는데
이문제를 해결하기 위해 C++ 은 가상상속이라는 새로운 개념을 도입하였다.
다이아몬드 상속 계층이 만들어지더라도 자식 개체 구조 내에 한번씩만 부모 클래스가 포함되도록 해준다.
프로그래밍의 종류
일반프로그래밍이란 ? STL 을 이용한 제네릭한 프로그램을 구현하는 패러다임을 말한다.
객체지향프로그래밍이란? 클래스를 사용하여 객체 중심적으로 생각하여 프로그램을 구현
'Programming' 카테고리의 다른 글
리눅스 사용자 관련 명령어 (0) | 2011.03.03 |
---|---|
CPPUNIT 테스트 (0) | 2011.01.07 |
IOCP 정리 (0) | 2010.12.02 |
SELECT 함수 정리 (0) | 2010.11.30 |
리눅스 SIGPIPE 처리 (0) | 2010.11.29 |