Programming

개인 순수 가상 기능의 요점은 무엇입니까?

procodes 2020. 6. 27. 15:03
반응형

개인 순수 가상 기능의 요점은 무엇입니까?


헤더 파일에서 다음 코드를 발견했습니다.

class Engine
{
public:
    void SetState( int var, bool val );
    {   SetStateBool( int var, bool val ); }

    void SetState( int var, int val );
    {   SetStateInt( int var, int val ); }
private:
    virtual void SetStateBool(int var, bool val ) = 0;    
    virtual void SetStateInt(int var, int val ) = 0;    
};

나에게 이것은 Engine클래스 또는 클래스에서 파생 된 클래스가 순수한 가상 함수에 대한 구현을 제공해야 함을 의미 합니다. 그러나 파생 클래스가 클래스를 다시 구현하기 위해 개인 함수에 액세스 할 수 있다고 생각하지 못했습니다. 그래서 왜 가상 클래스입니까?


이 주제의 질문은 매우 일반적인 혼란을 시사합니다. 혼란은 나쁜 것으로 보였기 때문에 C ++ FAQ가 개인용 가상 사용을 오랫동안 옹호 한 혼란은 충분히 일반적 입니다.

따라서 혼동을 먼저 제거하려면 : 예, 파생 클래스에서 개인용 가상 기능을 무시할 수 있습니다. 파생 클래스의 메서드는 기본 클래스에서 가상 함수를 호출 할 수 없지만 자체 구현을 제공 할 수 있습니다. Herb Sutter에 따르면 기본 클래스에 퍼블릭 비가 상 인터페이스와 파생 클래스에서 커스터마이즈 할 수있는 개인 구현을 통해 "구현 가능한 사용자 정의 동작의 사양에서 인터페이스 사양을 분리"할 수 있습니다. 그의 기사 "Virtuality" 에서 자세한 내용을 읽을 수 있습니다 .

그러나 당신이 제시 한 코드에는 흥미로운 점이 하나 더 있습니다. 공용 인터페이스는 오버로드 된 비가 상 함수 세트로 구성되며 해당 함수는 퍼블릭이 아닌 오버로드 된 가상 함수를 호출합니다. C ++ 세계에서와 마찬가지로이 용어는 관용구이며 이름이 있으며 물론 유용합니다. 이름은 (놀랍고 놀랍습니다!)

"퍼블릭 오버로드 된 비가 상 통화 보호 된 오버로드되지 않은 가상"

은닉 규칙올바르게 관리하는 데 도움이됩니다 . 여기 에서 자세한 내용을 읽을 수 있지만 잠시 설명하겠습니다.

Engine클래스 의 가상 함수 도 인터페이스이며 순수한 가상이 아닌 오버로드 된 함수 세트라고 상상해보십시오 . 순수한 가상이라면 아래 설명과 같이 여전히 동일한 문제가 발생할 수 있지만 클래스 계층 구조는 더 낮습니다.

class Engine
{
public:
    virtual void SetState( int var, bool val ) {/*some implementation*/}
    virtual void SetState( int var, int val )  {/*some implementation*/}
};

이제 파생 클래스를 만들고 싶다고 가정하고 두 개의 정수를 인수로 취하는 메소드에 대해서만 새로운 구현을 제공해야한다고 가정 해 봅시다.

class MyTurbochargedV8 : public Engine
{
public:
    // To prevent SetState( int var, bool val ) from the base class,
    // from being hidden by the new implementation of the other overload (below),
    // you have to put using declaration in the derived class
    using Engine::SetState;

    void SetState( int var, int val )  {/*new implementation*/}
};

파생 클래스에 using 선언을 넣지 않았거나 두 번째 오버로드를 재정의하는 것을 잊어 버린 경우 아래 시나리오에서 문제가 발생할 수 있습니다.

MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);

Engine회원 숨기기를 막지 않았다면 다음 과 같이 진술하십시오.

myV8->SetState(5, true);

void SetState( int var, int val )파생 클래스에서 호출 하여로 변환 true합니다 int.

인터페이스가 가상이 아니고 가상 구현이 공개되지 않은 경우 (예 : 파생 클래스의 경우) 파생 클래스의 작성자는 생각해 볼 문제가 적고 간단히 작성할 수 있습니다.

class MyTurbochargedV8 : public Engine
{
private:
    void SetStateInt(int var, int val )  {/*new implementation*/}
};

전용 순수 가상 기능은 비가 상 인터페이스 관용구 의 기본입니다 (OK, 항상 순수 가상은 아니지만 여전히 가상입니다). 물론 이것은 다른 것들에도 사용되지만 가장 유용합니다 (: 두 단어 : 공개 함수에서 처음에는 로깅, 통계 등과 같은 일반적인 것들을 넣을 수 있음) 함수의 끝에서 "가운데"를 사용하여이 전용 가상 함수를 호출하면 특정 파생 클래스에 따라 다릅니다.

class Base
{
    // ..
public:
    void f();
private:
    virtual void DerivedClassSpecific() = 0;
   // ..
};
void Base::f()
{
    //.. Do some common stuff
    DerivedClassSpecific();
    //.. Some other common stuff
}
// ..

class Derived: public Base
{
    // ..
private:
    virtual void DerivedClassSpecific();
    //..
};
void Derived::DerivedClassSpecific()
{
    // ..
}

Pure virtual - just obligates the derived classes to implement it.

EDIT: More about this: Wikipedia::NVI-idiom


Well, for one, this would allow a derived class to implement a function that the base class (containing the pure virtual function declaration) can call.


EDIT: Clarified statements about ability to override and ability to access/invoke.

It will be able to override those private functions. For example, the following contrived example works (EDIT: made derived class method private, and drop the derived class method invocation in main() to better demonstrate the intent of design pattern in use.):

#include <iostream>

class Engine
{
public:
  void SetState( int var, bool val )
  {
    SetStateBool( var, val );
  }

  void SetState( int var, int val )
  {
    SetStateInt( var, val );
  }

private:

    virtual void SetStateBool(int var, bool val ) = 0;
    virtual void SetStateInt(int var, int val ) = 0;

};

class DerivedEngine : public Engine
{
private:
  virtual void SetStateBool(int var, bool val )
  {
    std::cout << "DerivedEngine::SetStateBool() called" << std::endl;
  }

  virtual void SetStateInt(int var, int val )
  {
    std::cout << "DerivedEngine::SetStateInt() called" << std::endl;
  }
};


int main()
{
  DerivedEngine e;
  Engine * be = &e;

  be->SetState(4, true);
  be->SetState(2, 1000);
}

Private virtual methods in a base class like the ones in your code are typically used to implement the Template Method design pattern. That design pattern allows one to change the behavior of an algorithm in the base class without changing the code in the base class. The above code where the base class methods are invoked through a base class pointer is a simple example of the Template Method pattern.


Private virtual method is used for limiting the number of derived classes that can override the given function. The derived classes that has to override the private virtual method will have to be a friend of the base class.

A brief explanation can be found of DevX.com.


EDIT A private virtual method is effectively used in Template Method Pattern. The derived classes can override the private virtual method but the derived classes cannot call it's base class private virtual method (in your example, SetStateBool and SetStateInt). Only the base class can effectively call its private virtual method (Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected).

An interesting article can be found about Virtuality.


TL;DR answer:

You can treat it like another level of encapsulation - somewhere between protected and private: you can't call it from child class, but you can override it.

It is useful when implementing Template Method design pattern. You could use protected, but private together with virtual may be considered as better choice, because of better encapsulation.

참고URL : https://stackoverflow.com/questions/3970279/what-is-the-point-of-a-private-pure-virtual-function

반응형