업데이트:

태그: ,

카테고리:



REF : 윤성우의 열혈 C++

가상함수와 멤버함수

멤버함수

  • 객체를 생성할때마다 함수를 생성하는 것은 굉장한 메모리낭비가 아닐 수 없다.
  • 멤버함수는 객체에 종속되는 개념이 아닌, 클래스에 종속되는 개념으로 존재한다.
    • 클래스마다 존재한다.
    • 클래스의 자료형으로 생성된 모든 객체가 멤버함수를 공유한다.


가상함수의 동작원리와 가상함수 테이블

  • 한개 이상의 가상함수를 포함하는 추상클래스는 컴파일러가 가상함수 테이블을 만든다.
    • 이는 실제 호출되어야 할 함수의 위치정보를 담는 테이블이다.
    • 이를 V-Table이라고도 한다.
  • 오버라이딩된 가상함수의 주소정보는 유도 클래스의 가상함수 테이블에 포함되지 않으므로,
    • 가장 마지막에 오버라이딩 한 유도클래스의 멤버함수가 호출된다.
#include <iostream>
using namespace std;


class AAA
{
	private:
		int num1;
	public:
		virtual void Func1() {cout<<"Func1"<<endl;}
		virtual void Func2() {cout<<"Func2"<<endl;}
};

class BBB: public AAA
{
	private:
		int num2;
	public:
		virtual void Func1() {cout<<"BBB::Func1"<<endl;}
		void Func3() {cout<<"Func3"<<endl;}
};

int main(void)
{
	AAA *aptr = new AAA();
	aptr->Func1();

	BBB *bptr = new BBB();
	bptr->Func1();
	return 0;
}


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

  • 위의 그림처럼 가상함수를 가진 클래스는 가상함수 테이블이 만들어진다.
  • 그리고 이 클래스로 객체를 생성하게되면 이 객체에는 가상함수 테이블의 주소값이 저장되는데, 실제로 우리가 사용할 수는 없다.
    • 다만, 가상함수 테이블이 만들어지고, 참조하는 과정이 추가되므로 실행속도가 저하되지만, 속도차이는 미미하다.



다중상속에 대한 이해

견해

  • 다중상속은 득보다 실이 많은 문법인가?
    • 일반적인 경우에서 많은 문제가 발생한다.
    • 따라서 가급적 사용하지 말아야하나, 제한적인 상황에서는 사용해야한다.
  • 공부하지 않아도 되는가?
    • 다중상속은 우리가 직접 구현할 필요가 없을수도 있으나,
    • 다른 라이브러리가 사용했을수도 있으니, 기본적인 이해는 필요하다.
  • 사용법
    • 상속의 대상이되는 클래스를 구분해서 명시할 수 있다.
    • 기초 클래스를 상속하는 형태는 각각 별도로 지정할 수 있다.

        class A
        {};
      
        class B
        {};
      
        class AB : public A, protected B
        {};
      


다중상속의 문제점

  1. 모호성
    • 다른 기초클래스에 동일한 멤버가 존재하는 경우에 유도클래스 내에서 멤버이름만으로 접근할 수 없다.
    • 이름공간을 명시하면 가능하다.
        class A
        {
            public:
                void simplefnc();
        };
      
        class B
        {
            public:
                void simplefnc();
        };
      
        class AB : public A, protected B
        {
            public:
                void exec()
                {
                    A::simplefnc(); //namespace 붙여서
                    B::simplefnc(); //어느 클래스의 함수를 호출할것인지 명시
                }
        };
      


  1. 가상상속
    • 만약 가장 상위클래스를 기초클래스로 하는 유도 클래스 2개를 다중상속한다고 할때,
        class Z
        {
            public:
                void basefnc();
        };
        class A : public Z
        {
            public:
                void simplefnc();
        };
      
        class B : public Z
        {
            public:
                void simplefnc();
        };
      
        class AB : public A, public B
        {
            public:
                void exec()
                {
                    A::basefnc(); //namespace 붙여서
                    B::basefnc(); //어느 클래스의 함수를 호출할것인지 명시
                }
        };
      
      • 이런식으로 상속하게되면 AB 객체는 Z라는 기초 클래스 멤버를 2개나 가지게된다.
        • 이에따라, Z클래스의 생성자가 2번호출된다.
        • 최상위 기초클래스의 멤버를 가져올때도 어떤 유도클래스(A,B)의 기초 클래스 멤버 Z로부터 가져올 지 명시해줘야한다.
      • 대부분의 경우, 클래스 AB가 간접상속한 Z는 1개만 존재하는게 타당한데,
        • 이를 가능케하는게 가상 상속이다.
            class Z
            {
                public:
                    void basefnc();
            };
            class A : virtual public Z
            {
                public:
                    void simplefnc();
            };
          
            class B : virtual public Z
            {
                public:
                    void simplefnc();
            };
          
            class AB : public A, public B
            {
                public:
                    void exec()
                    {
                        basefnc(); //namespace 붙여서
                    }
            };
          
          • 가상상속을 통해, Z클래스의 멤버는 1개만 존재하게된다.

댓글남기기