삶의 공유

[C++] 정적 결합, 동적 결합 본문

Programing/C++

[C++] 정적 결합, 동적 결합

dkrehd 2021. 1. 25. 22:35
728x90
반응형

Summary)

정적 결합

 : 가리키고 있는 타입이 아니라 스스로, 변수(객체)의 타입만 보고 어떤 함수로 갈지를 결정 한 것이다. 이렇게 객체의 타입만 보고 가는 것을 정적 결합이라고 한다. 다시 얘기하면 컴파일 타임에 어떤 것을 호출할지 이미 결정하는 것을 정적 결합

예 ) 함수 오버로딩

동적 결합

런타임 바인딩, 즉 런타임 도중에 타입이 결정되는 것을  동적 바인딩이라고 한다. 

예 ) 함수 오버라이딩

 

 

 

오버로딩에 대해 알아보자.

#include <iostream>
using namespace std;

class A
{
public:
    int num;
};
class B : public A
{

};

A operator+(const A& x, const A& y)
{
    A a;
    a.num = x.num + y.num;
    return a;
}

B operator+(const B& x, const B& y) // 오버로딩 규칙에 의해서 이 함수로 적용이 된다.(좀더 구체적으로 기술이 되어 있기 때문에.)
{
    B b;
    b.num = x.num * y.num;
    return b;
}


int main()
{
    B a0, a1;
    a0.num = 10;
    a1.num = 20;
    A a2 = a0 + a1;
    cout << a2.num << endl;
}

이 예제의 실행 결과는 200이다.

 

이유는 오버로딩 규칙에 의해서 좀더 구체적으로 기술되어 있는 B operator+(const B& x, const B& y) 구문으로 적용 되기 떄문이다

여기까지는 크게 어렵지 않다.

 

하지만 이 예제를 살펴 보자

#include <iostream>
using namespace std;

class A
{
public:
    int num;
};
class B : public A
{

};

A operator+(const A& x, const A& y)
{
    A a;
    a.num = x.num + y.num;
    return a;
}

B operator+(const B& x, const B& y) // 오버로딩 규칙에 의해서 이 함수로 적용이 된다.(좀더 구체적으로 기술이 되어 있기 때문에.)
{
    B b;
    b.num = x.num * y.num;
    return b;
}


int main()
{
    B b0, b1;
    b0.num = 10;
    b1.num = 20;

    A& a0 = b0;
    A& a1 = b1;

    A a2 = a0 + a1;
    cout << a2.num << endl;
}

실행 결과는 30이다.

a0 = b0 / a1 = b1 으로 되어 있으나, 가리키고 있는 타입이 아니라 스스로, 변수(객체)의 타입만 보고 어떤 함수로 갈지를 결정 한 것이다. 

이렇게 객체의 타입만 보고 가는 것을 정적 결합이라고 한다.

다시 얘기하면 컴파일 타임에 어떤 것을 호출할지 이미 결정하는 것을 정적 결합

즉, 함수 오버로딩은 정적 결합이다.

※ 오버로딩은 디버거를 통해서라도 런타임 도중에 변경이 불가능하다.

 

 

이번엔 오버라이딩에 대해서 알아보자

 

#include <iostream>
using namespace std;

class Animal
{
public:
    virtual void eat() const
    {
        cout << "냠" << endl;
    }
};

class Cat : public Animal
{
public:
    virtual void eat() const override
    {
        cout << "냥" << endl;
    }
};

class Dog : public Animal
{
public:
    virtual void eat() const override
    {
        cout << "냥" << endl;
    }
};


int main()
{
    Animal* a = new Dog();
    a->eat(); // 가리키고 있는 객체의 함수를 호출함
    // 런타임 도중에 매번 가리키고 있는 함수를 찾음 (런타임 바인딩임.)
}

 

오버라이딩의 경우는 런타임 도중에 매번 가리키고 있는 함수를 찾음 (런타임 바인딩임.)

런타임 바인딩, 즉 런타딤 도중에 타입이 결정되는 것을  동적 바인딩이라고 한다. 

※ virtual키워드르 붙이면 동적 바인딩이다. 만약 virtual을 붙이지 않으면 정적 바인딩이다.

※ 런타임 도중에 변경이 가능하다 (디버거를 통해서)

 

위의 Animal Class에서 포인터 변수를 넣고 사이즈를 컴파일 해보면 8byte의 사이즈가 된다. 이것은 virtual키워드를 넣으면 포인터로 추측되는 무언가가 있다고 추측을 할 수 있다.

 

즉 virtual 키워드가 있으면,  이 가상 함수를 가르키는 포인터가 있는것이다.

 

예제를 보면,

#include <iostream>
using namespace std;

class Animal
{
public:
    int* p;
    virtual void eat() const
    {
        cout << "냠" << endl;
    }
    virtual void foo()
    {
        cout << "foo " << endl;
    }
};

class Cat : public Animal
{
public:
    virtual void eat() const override
    {
        cout << "냥" << endl;
    }
};

class Dog : public Animal
{
public:
    virtual void eat() const override
    {
        cout << "냥" << endl;
    }
};


int main()
{
    Dog d;
    Animal* animal = new Cat; // 부모가 자식을 가르킬때는 가상함수 메카니즘에 의해 가상함수 테이블을 통해 런타임 도중에 함수를 찾는다
    animal->eat(); // 런타임 도중에 최적의 함수인 오버라이딩에 의해 "냥"을 출력한다.
}

 

 

 

 

반응형