[전재] 허함수와 구조함수, 분석함수

4999 단어
원문 주소: 시나닷컴 블로그 | zjdtc | 허함수와 구조함수, 분석함수 | 2011-06-22 본고는 원문에 개인적인 문제와 이해를 증가시켰다.

구조 함수는 허함수일 수 없다


4
  • 저장 공간의 측면에서 허함수는 하나의 vtable에 대응한다. 이 vtable는 대상의 메모리 공간에 저장된 것이다. 즉, 만약에 구조 함수가 허함수라면 vtable를 통해 호출해야 하는데 대상은 구조 함수를 통해 실례화된 것이다. 실례화하기 전에 메모리 공간이 없다('닭이 먼저 있느냐, 알이 먼저 있느냐'는 문제가 파생된다). 그래서 구조 함수는 허함수가 될 수 없다

  • 4
  • 사용 각도에서 허함수는 주로 정보가 완전하지 않은 상황에서 다시 불러오는 함수를 대응하는 호출에 사용한다. 특히 인터페이스만 알고 정확한 대상 유형을 모르는 함수를 호출할 수 있다.구조 함수 자체는 대상을 초기화하는 것이기 때문에 대상의 정확한 유형을 알아야 하기 때문에 구조 함수는 허함수가 될 수 없다

  • 4
  • 작용허함수의 작용은 기류의 지침이나 인용을 통해 그것을 호출할 때 파생류를 호출하는 구성원 함수로 변할 수 있고 구조함수는 대상을 만들 때 자동으로 호출되며 기류의 지침이나 인용을 통해 호출할 수 없으며 구조함수는 허함수가 될 수 없다

  • 4
  • vtable은 구조 함수를 호출한 후에야 만들어졌기 때문에 구조 함수는 허함수가 될 수 없다.구조 함수를 호출할 때 대상의 실제 유형을 확정할 수 없다. 파생류는 기류의 구조 함수를 호출할 수 있고 구조 함수의 역할은 초기화를 제공하는 것이다. 대상의 생명기에 한 번만 실행하고 대상의 동적 행위가 아니며 허함수가 될 필요도 없다

  • 분석 함수는 허함수일 수도 있고, 심지어는 순허함수일 수도 있다


    대상을 대상으로 프로그래밍하는 과정에서 기류의 바늘이나 인용은 보통 기류나 파생류의 대상을 가리킨다. 만약에 기류의 분석 함수가 허함수가 아니라면 바늘이나 인용을 삭제하여 대상을 방출할 때 기류의 분석 함수만 호출하고 파생류의 분석 함수는 호출하지 않아 메모리가 유출된다.반대로 만약에 기류의 분석 함수가 허함수라면 이런 문제가 발생하지 않을 것이다.따라서 하나의 클래스가 다른 클래스의 기본 클래스로 사용되려고 할 때, 그 분석 함수는 반드시 허함수여야 한다.다음과 같은 예를 고려하십시오.
    class A
    {
    public:
        A() { ptra_ = new char[10];}
        ~A() { delete[] ptra_;} //  
    private:
        char * ptra_;
    };
    
    class B: public A
    {
    public:
        B() { ptrb_ = new char[20];}
        ~B() { delete[] ptrb_;}
    private:
        char * ptrb_;
    };
    
    void foo()
    {
        A * a = new B();
        delete a;
    }
    

    이 예에서 delete a를 실행할 때 실제로는 A:~A()만 호출되었고 B류의 분석 함수는 호출되지 않았다.위의 A::~A()를virtual로 바꾸면 B::~B()도 deletea에서 호출되었음을 보증할 수 있습니다.따라서 기류의 분석 함수는 모두virtual이어야 한다.그러나 일반적으로 기본 클래스의 클래스 분석 함수를 하지 않으면 허함수라고 성명하지 않는다. 허함수의 실현은 대상이 추가 정보를 가지고 시스템 비용을 추가해야 하기 때문에 대상의 메모리 공간에 vptr를 추가해야 한다. 이 바늘은 vtable을 가리킨다.분석 함수는 순허함수일 수 있다. 보통 하나의 클래스를 추상류로 설정하고 이 클래스가 적당한 함수가 순허화될 수 없을 때 순허의 분석 함수를 사용하여 목적을 달성할 수 있다.그러나 순수 허의 분석 함수는 다른 순수 허 함수와 다르다는 점은 순수 허의 분석 함수는 그 정의를 제공해야 하고 다른 순수 허 함수는 성명만 제공하면 된다는 것이다. 왜냐하면 파생 클래스의 대상을 방출할 때 그 분석 함수는 최종적으로 추상 클래스와 같은 층으로 호출되고 추상 클래스의 허구 함수를 호출하며 추상 클래스의 분석 함수가 정의되지 않으면 컴파일할 때 오류가 발생할 수 있기 때문이다.

    다태와 허함수


    허함수는 C++에서 다태적 실현을 위한 메커니즘으로 핵심 이념은 기본 클래스를 통해 파생 클래스 정의에 접근하는 함수이다.

    다태적 용도


    대상을 대상으로 하는 프로그래밍에서 먼저 데이터에 대해 추상적(기본 클래스 확정)과 계승(파생 클래스 확정)을 하고 클래스 차원을 구성한다.이 클래스의 사용자가 그들을 사용할 때 만약에 클래스가 필요할 때 클래스에 대한 코드를 쓰고 파생 클래스가 필요할 때 파생 클래스에 대한 코드를 쓰면 클래스가 사용자 앞에 완전히 노출되는 것과 같다.만약 이 클래스의 차원에 어떤 변화가 있다면 (새로운 클래스가 추가되었음) 사용자가 알아야 한다. (새로운 클래스에 대한 코드 쓰기)이렇게 하면 클래스 차원과 사용자 간의 결합을 증가시켰다. 어떤 사람들은 이런 상황을 프로그램의'bad smell'중 하나로 열거했다.다태는 프로그래머로 하여금 이런 곤경에서 벗어나게 할 수 있다. 하나의 기본 지침이나 인용을 통해 하나의 허함수를 호출하면 서로 다른 파생류의 함수를 실제적으로 호출하는 효과를 얻을 수 있고 클래스 차원과 사용자 간의 결합을 낮출 수 있다.

    동적 연결 방법


    컴파일러는 어떻게 허함수에 대해 다시 실행할 때 호출된 함수를 확정할 수 있는 코드를 생성합니까?즉, 허함수는 실제로 어떻게 컴파일러에 의해 처리됩니까?Lippman은 C++ 대상 모델을 깊이 있게 탐색했다[1]에서 서로 다른 장에서 몇 가지 방식을 설명했는데 여기서'표준적인'방식을 간단하게 소개한다.'표준'방식, 즉'vtable'메커니즘.컴파일러는 클래스에virtual로 명시된 함수가 있음을 발견하면, 이를 위해 허함수표, 즉 vtable를 생성합니다.vtable는 실제적으로 함수 바늘의 수조로 모든 허함수가 슬로트를 차지한다.하나의 클래스는 대상이 몇 개든지 상관없이 vtable만 있습니다.파생류는 자신의 vtable가 있지만 파생류의 vtable는 기본 클래스의 vtable와 같은 함수 배열 순서가 있고 같은 이름의 허함수는 두 그룹의 같은 위치에 놓여 있다.클래스 대상을 만들 때, 컴파일러는 모든 실례의 메모리 레이아웃에 vptr 필드를 추가합니다. 이 필드는 클래스의 vtable을 가리킵니다.이러한 수단을 통해 컴파일러는 빈 함수 호출을 볼 때 이 호출을 덮어씁니다.
    void bar(A * a){ a->foo(); }
    

    다음으로 덮어쓰기:
    void bar(A * a){ (a->vptr[1])(); }
    

    파생 클래스와 기본 클래스의foo () 함수는 같은 vtable 인덱스를 가지고 있고, 그들의 vptr는 다른 vtable를 가리키기 때문에, 이러한 방법을 통해 실행 시간에 어떤foo () 함수를 호출할지 결정할 수 있습니다.실제 상황은 결코 이렇게 간단하지 않지만 기본 원리는 대체로 이렇다.

    구조 함수와 분석 함수 중의 허함수 호출


    하나의 종류의 허함수가 자신의 구조 함수와 분석 함수에서 호출될 때, 그것들은 보통 함수로 변하여 허함수가 되지 않는다.즉 구조 함수와 분석 함수에서 자신을'다태적'으로 만들 수 없다는 것이다.구조 함수 내부에 허함수가 있을 때 자신의 클래스에 있는 허함수만 호출한다. 호출할 때 파생 클래스 버전의 정보가 없기 때문이다.분석 함수 내부에 허함수가 있을 때 구조 함수와 같이'국부'버전만 호출된다. 파생류 버전의 정보가 신뢰할 수 없기 때문이다.분석 함수의 호출 순서는 구조 함수와 반대로 파생류의 분석 함수에서 기류의 분석 함수까지이다.어떤 클래스의 분석 함수가 호출되었을 때 이 클래스에서 파생된 클래스의 분석 함수는 이미 호출되었고 상응하는 데이터도 잃어버렸다. 만약에 허함수의 마지막 버전을 다시 호출한다면 신뢰할 수 없는 데이터에 대해 조작하는 것과 같아서 이것은 매우 위험하다.따라서 분석 함수에서 허함수 메커니즘도 작용하지 않는다.

    허함수 사용 시기


    기류를 설계할 때, 만약 함수가 파생류에서 서로 다른 표현을 필요로 하는 것을 발견한다면, 그것은 반드시 허구일 것이다.디자인의 측면에서 볼 때 기류에 나타난 허함수는 인터페이스이고 파생류에 나타난 허함수는 인터페이스의 구체적인 실현이다.이런 방법을 통해 대상의 행위를 추상화할 수 있다.

    Things to Remember


    4
  • 하나의 함수를 허함수로 정의하는데 함수가 실현되지 않는 함수는 아니다.그것을 허함수로 정의하는 것은 기본 클래스의 바늘로 하위 클래스의 이 함수를 호출하는 것을 허용하기 위해서이다

  • 4
  • 하나의 함수를 순허함수로 정의해야 함수가 실현되지 않았다는 것을 의미한다.정의는 하나의 인터페이스를 실현하고 규범화된 역할을 하기 위해 이를 규범화하고 계승하며 클래스의 프로그래머는 반드시 이 함수를 실현해야 한다

  • 4
  • 순허함수가 있는 클래스는 클래스 대상을 생성할 수 없고 순허함수가 없으면 된다

  • 4
  • 다태는 일반적으로 기류를 가리키는 지침을 통해 이루어진다

  • 문제: 만약에 기류에서 어떤 함수를 허함수로 성명한다면 두 파생류 중 하나는 이 함수를 다시 정의하고 다른 하나는 이 함수를 허함수로 성명하면 두 파생류의 허함수표는 무엇이 다릅니까?(답안은'참고문'의'C++ 허함수표 분석'참조)

    참고 문장


    1. CSDN | haozlee | Leo의 블로그 | C++ 허함수표 분석

    좋은 웹페이지 즐겨찾기