가상함수의 동작원리




A 클래스를보면 virtual 가상함수가 존재한다. 이렇듯 한 개 이상의 가상함수를 포함하는 클래스에 대해서는 컴파일러가 "가상함수 테이블" 이란 것을 만든다. 

이를 간단히 "V-Table(virtual table)" 이라고도 하는데, 이는 실제 호출되어야 할 함수의 위치정보를 담고 있는 테이블 이다.


가상테이블을 확인하면 A 클래스의 Func1에 대한 정보가 존재하지 않는다. 


- 이렇듯, 오버라이딩 된 가상함수의 주소정보는 유도 클래스의 가상함수 테이블에 포함되지 않는다. 때문에 오버라이딩 된 가상함수를 호출하면, 무조건 가장 마지막에 오버라이딩을 한 유도 클래스의 멤버함수가 호출되는 것이다.




가상함수 테이블이 참조되는 방식


- main 함수가 호출되기 이전에 가상함수 테이블이 메모리 공간에 할당된다. 참고도 가상함수 테이블은 객체의 생성과 상관없이 메모리 공간에 할당된다. 

이는 가상함수 테이블이 멤버함수의 호출에 사용되는 일종의 데이터이기 때문이다. 


※ 가삼함수를 하나이상 멤버로 지니는 클래스의 객체에는 가상함수 테이블의 주소 값이 저장된다. 물론 이 주소 값은 우리가 직접 참조할 수 있는 주소 값이 아니다. 내부적으로 필요에 의해서 참조되는 주소 값일 뿐이다.



>>>>>> 결론


# B 클래스의 가상함수를 살펴보면, 오버라이딩 된 A 클래스의 Func1 함수에 대한 정보가 없음을 알 수 있다. 

그래서 B클래스의 Func1 함수가 대신 호출되는데, 이것이 바로 가상함수의 호출원리이다.



※ 가상함수 테이블에 의한 속도의 저하

- 위에서 설명했듯이 클래스에 가상함수가 포함되면, 가상함수 테이블이 생성되고, 또 이 테이블을 참조하여 호출될 함수가 결정되기 때문에 실행속도가 감소하기 마련이다. 하지만 그 속도의 차이가 극히 미미하고 또 이러한 단점에도 불구하고 가상함수는 많은 장점을 제공하기 때문에 유용하게 활용되는 것이다.

Posted by scii
:

캡슐화

Programming/C++ 2012. 5. 12. 02:11 |
캡슐화
:하나의 목적 하에 둘 이상의 기능이 모여서 하나의 목적을 달성.

캡슐화에는 정보은닉이 기본적으로 포함된다.

캡슐화는 감싸는 개념이다. 그런데 감싸려면 안전하게 감싸야 한다. 다시 말해서 이왕이면 멤버변수가 보이지 않게 정보를 은닉해서 감싸는 것이 좋다. 그래서 캡슐화는 기본적으로 정보은닉을 포함하는 개념이라고 이야기한다.

※ 캡슐화는 어려운 개념이다. 왜냐하면 캡슐화의 범위를 결정하는 일이 쉽지 않기 때문이다.

#include <iostream>


using namespace std;


class Point 

{

    private:

        int xpos, ypos;


    public:

        void Init(int x, int y)

        {

            xpos = x;

            ypos = y;

        }

        

        void ShowPointInfo(void) const

        {

            cout<<"["<<xpos<<", "<<ypos<<"]"<<endl;

        }

};


class Circle 

{

    private:

        int rad;

        Point p;


    public:

        void Init(int x, int y, int r)

        {

            rad = r;

            p.Init(x, y);

        }


        void Show(void) const

        {

            cout<<"radius: "<<rad<<endl;

            p.ShowPointInfo();

        }

};


class Ring

{

    private:

        Circle c1;

        Circle c2;


    public:

        void Init(int x1, int y1, int r1, int x2, int y2, int r2)

        {

            c1.Init(x1, y1, r1);

            c2.Init(x2, y2, r2);

        }


        void ShowRingInfo(void) const

        {

            cout<<"Inner Circle Info..."<<endl;

            c1.Show();

            cout<<"Outter Circle Info..."<<endl;

            c2.Show();

        }

};


int main(void)

{

    Ring ring;

    ring.Init(1, 1, 4, 2, 2, 9);

    ring.ShowRingInfo();

    return 0;

}


이 코드에서 주목할 점.


Ring 클래스, Circle 클래스, Point 클래스 모두 자신의 정보를 출력하기 위한 함수를 멤버에 포함시켜서 캡슐화를 완성하였다.

'Programming > C++' 카테고리의 다른 글

이니셜라이저(Initializer)  (0) 2012.05.19
생성자(Constructor)  (0) 2012.05.12
const 함수  (2) 2012.05.08
정보은닉(Information Hiding)  (0) 2012.05.03
Message Passing  (0) 2012.05.02
Posted by scii
:

클래스는 객체의 생성을 목적으로 디자인한다.


좋은 클래스가 되기 위한 최소한의 조건은 무엇일까?


ⓐ 정보은닉

ⓑ 캡슐화


이 두가지는 꼭 생각하며 클래스를 디자인해야 한다.


정보은닉을 하는 이유? 

제한된 방법으로의 접근만 허용을 해서 잘못된 값이 저장되지 않도록 하는데 있다. 또 실수를 했을 때, 실수가 쉽게 발견되도록 하는데 있다.


만약, 멤버변수가 직접적으로 접근이 가능하다면, 그리고 그곳에 음수가 들어가면 안되는 곳이라면.. 직접접근을 했을 때 위험에 노출된다. 

하지만 멤버변수를 private으로 설정하고 함수로만 멤버변수에 접근이 가능하도록 디자인한다면!!! 그 함수만 잘 만들면 잘못된 값의 저장을 막을 수 있다. 

이렇듯, 정보은닉은 꼭 생각하며 클래스를 디자인해야 한다.




코드에 있는 int GetX() const,   bool GetX(int xpos) 함수들을 가리켜 "엑세스 함수(access function)"이라고 한다. 이들은 멤버변수를 private으로 선언하면서 클래스 외부에서의 멤버변수 접근을 목적으로 정의되는 함수들이다.


보통 Get함수이름, Set함수이름을 쓴다. Get은 값을 리턴하는 목적이고, Set값을 대입하는 목적이다.


※ 지금 당장은 필요치 않지만 필요할 수 있다고 판단되는 함수들도 더불어 멤버에 포함시키는 경우도 많다. 대표적인 예가 '엑세스 함수'들이다.


'Programming > C++' 카테고리의 다른 글

생성자(Constructor)  (0) 2012.05.12
캡슐화  (0) 2012.05.12
const 함수  (2) 2012.05.08
Message Passing  (0) 2012.05.02
클래스 기반의 두 가지 객체생성 방법  (0) 2012.05.02
Posted by scii
:

Message Passing

Programming/C++ 2012. 5. 2. 22:30 |

관계를 형성하는 둘 이상의 클래스


하나의 독립된 클래스를 정의하는 것은 쉽다. 그러나 둘 이상의 클래스를 정의하되, 아래처럼 관계를 형성해서 정의하는 것은 쉽지 않다. 

하지만 이는 매우 중요하다. 단순히 함수호출로 이해하면 별 것 아니지만, 메시지 전달의 관점에서 보면 이는 매우 중요하다.


#include <iostream>

using namespace std;


class FruitSeller

{

private:

int numOfApple;

int totalMoney;

int APPLE_PRICE;

public:

void InitMember(int price, int num)

{

numOfApple = num;

APPLE_PRICE = price;

totalMoney = 0;

}

int SellFuit(int money)

{

int n = money/APPLE_PRICE;

numOfApple-=n;

totalMoney += money;

return n;

}

void ShowSeller(void)

{

cout<<"판매자의 남은 사과: "<<numOfApple<<endl;

cout<<"판매자의 현재 돈 : "<<totalMoney<<endl<<endl;

}

int gg;

};


class FruitBuyer

{

private:

int numOfApple;

int totalMoney;

public:

void InitMember(int money)

{

numOfApple = 0;

totalMoney = money;

}

void BuyFuit(FruitSeller &seller, int money) // 메시지 패싱. &를 이용하여 seller에게 접근(call-by-reference).

{

totalMoney -= money;

numOfApple += seller.SellFuit(money); //이 문장은 seller야 나에게 사과 2000원어치 줘라라는 뜻이된다.

}

void ShowBuyer(void)

{

cout<<"구매자의 소유한 사과: "<<numOfApple<<endl;

cout<<"구매자의 현재 돈 : "<<totalMoney<<endl<<endl;

}

};


int main(void)

{

FruitSeller seller;

seller.InitMember(1000, 20);

seller.ShowSeller();


FruitBuyer buyer;

buyer.InitMember(5000);

buyer.ShowBuyer();

buyer.BuyFuit(seller, 2000);  //seller에게 2000을 건내주고 있다.


seller.ShowSeller();

buyer.ShowBuyer();


return 0;

}



'Programming > C++' 카테고리의 다른 글

생성자(Constructor)  (0) 2012.05.12
캡슐화  (0) 2012.05.12
const 함수  (2) 2012.05.08
정보은닉(Information Hiding)  (0) 2012.05.03
클래스 기반의 두 가지 객체생성 방법  (0) 2012.05.02
Posted by scii
:

ClassName objName;  // 일반적인 변수의 선언방식으로 객체생성.

ClassName * ptrObj = new ClassName;  // 동적 할당방식(힙 할당방식)으로 객체생성.


'Programming > C++' 카테고리의 다른 글

생성자(Constructor)  (0) 2012.05.12
캡슐화  (0) 2012.05.12
const 함수  (2) 2012.05.08
정보은닉(Information Hiding)  (0) 2012.05.03
Message Passing  (0) 2012.05.02
Posted by scii
: