암시 적 인터페이스와 명시 적 인터페이스


9

나는 컴파일 타임 다형성과 런타임 다형성의 실제 한계를 이해한다고 생각합니다. 그러나 명시 적 인터페이스 (런타임 다형성, 즉 가상 함수 및 포인터 / 참조)와 암시 적 인터페이스 (컴파일 타임 다형성, 즉 템플릿)의 개념적 차이점은 무엇입니까 ?

내 생각은 동일한 명시 적 인터페이스를 제공하는 두 개의 객체는 동일한 유형의 객체 (또는 공통 조상을 가져야 함)이어야하지만 동일한 암시 적 인터페이스를 제공하는 두 개의 객체는 동일한 유형의 객체 일 필요는 없으며 암시 적을 제외해야합니다. 둘 다 제공하는 인터페이스는 기능이 매우 다를 수 있습니다.

이것에 대한 생각?

그리고 두 개의 객체가 동일한 암시 적 인터페이스를 제공하는 경우 가상 객체 조회 테이블과 함께 동적 디스패치가 필요하지 않은 기술적 이점 외에도 이러한 객체가 해당 인터페이스를 선언하는 기본 객체에서 상속하지 않는 이유는 무엇입니까? 그것을 명시적인 인터페이스로 만들고 있습니까? 그것을 말하는 또 다른 방법 : 동일한 암시 적 인터페이스를 제공하고 따라서 샘플 템플릿 클래스의 유형으로 사용할 수있는 두 개의 객체가 해당 인터페이스를 명시 적으로 만드는 기본 클래스에서 상속해서는 안되는 경우를 알려주시겠습니까?

관련 게시물 :


이 질문을보다 구체적으로 만드는 예는 다음과 같습니다.

암시 적 인터페이스 :

class Class1
{
public:
  void interfaceFunc();
  void otherFunc1();
};

class Class2
{
public:
  void interfaceFunc();
  void otherFunc2();
};

template <typename T>
class UseClass
{
public:
  void run(T & obj)
  {
    obj.interfaceFunc();
  }
};

명시 적 인터페이스 :

class InterfaceClass
{
public:
  virtual void interfaceFunc() = 0;
};

class Class1 : public InterfaceClass
{
public:
  virtual void interfaceFunc();
  void otherFunc1();
};

class Class2 : public InterfaceClass
{
public:
  virtual void interfaceFunc();
  void otherFunc2();
};

class UseClass
{
public:
  void run(InterfaceClass & obj)
  {
    obj.interfaceFunc();
  }
};

보다 심층적이고 구체적인 예 :

다음과 같은 방법으로 일부 C ++ 문제를 해결할 수 있습니다.

  1. 템플릿 유형이 암시 적 인터페이스를 제공하는 템플릿 클래스
  2. 명시 적 인터페이스를 제공하는 기본 클래스 포인터를 사용하는 템플릿이 아닌 클래스

변경되지 않는 코드 :

class CoolClass
{
public:
  virtual void doSomethingCool() = 0;
  virtual void worthless() = 0;
};

class CoolA : public CoolClass
{
public:
  virtual void doSomethingCool()
  { /* Do cool stuff that an A would do */ }

  virtual void worthless()
  { /* Worthless, but must be implemented */ }
};

class CoolB : public CoolClass
{
public:
  virtual void doSomethingCool()
  { /* Do cool stuff that a B would do */ }

  virtual void worthless()
  { /* Worthless, but must be implemented */ }
};

사례 1 . 명시 적 인터페이스를 제공하는 기본 클래스 포인터를 사용하는 템플릿이 아닌 클래스입니다.

class CoolClassUser
{
public:  
  void useCoolClass(CoolClass * coolClass)
  { coolClass.doSomethingCool(); }
};

int main()
{
  CoolA * c1 = new CoolClass;
  CoolB * c2 = new CoolClass;

  CoolClassUser user;
  user.useCoolClass(c1);
  user.useCoolClass(c2);

  return 0;
}

사례 2 . 템플릿 유형이 암시 적 인터페이스를 제공하는 템플릿 클래스 :

template <typename T>
class CoolClassUser
{
public:  
  void useCoolClass(T * coolClass)
  { coolClass->doSomethingCool(); }
};

int main()
{
  CoolA * c1 = new CoolClass;
  CoolB * c2 = new CoolClass;

  CoolClassUser<CoolClass> user;
  user.useCoolClass(c1);
  user.useCoolClass(c2);

  return 0;
}

사례 3 . 그 템플릿 유형 템플릿 기반 클래스로부터 도출되지 암시 인터페이스 (이 시간을 제공한다 CoolClass:

class RandomClass
{
public:
  void doSomethingCool()
  { /* Do cool stuff that a RandomClass would do */ }

  // I don't have to implement worthless()! Na na na na na!
}


template <typename T>
class CoolClassUser
{
public:  
  void useCoolClass(T * coolClass)
  { coolClass->doSomethingCool(); }
};

int main()
{
  RandomClass * c1 = new RandomClass;
  RandomClass * c2 = new RandomClass;

  CoolClassUser<RandomClass> user;
  user.useCoolClass(c1);
  user.useCoolClass(c2);

  return 0;
}

사례 1에서는 전달되는 객체가 (및 구현 ) useCoolClass()의 자식이어야합니다 . 사례 2와 3은, 다른 한편으로는, 소요됩니다 어떤 이 클래스 기능을.CoolClassworthless()doSomethingCool()

코드 사용자가 항상 훌륭한 서브 클래 싱 CoolClass이라면 사례 1은 CoolClassUser항상의 구현을 기대하기 때문에 직관적 인 의미 가 있습니다 CoolClass. 그러나이 코드가 API 프레임 워크의 일부라고 가정하면 사용자가 함수 CoolClass가있는 자체 클래스 를 서브 클래스 화 하거나 롤링 할지 여부를 예측할 수 없습니다 doSomethingCool().


어쩌면 내가 누락 된 것이 있지만 첫 번째 단락에서 이미 간결하게 언급 된 중요한 차이점은 아닙니다. 즉, 명시 적 인터페이스는 런타임 다형성이며 암시 적 인터페이스는 컴파일 타임 다형성입니다.
Robert Harvey

2
명시 적 인터페이스를 제공하는 추상 클래스에 대한 포인터를 가져 오는 클래스 또는 함수 또는 암시 적 인터페이스를 제공하는 오브젝트를 사용하는 템플리트 화 된 클래스 또는 함수를 사용하여 해결할 수있는 몇 가지 문제점이 있습니다. 두 솔루션 모두 작동합니다. 첫 번째 솔루션을 언제 사용 하시겠습니까? 두번째?
Chris Morris

개념을 조금 더 열면 이러한 고려 사항이 대부분 사라진다고 생각합니다. 예를 들어, 비 상속 정적 다형성에 어디에 적합할까요?
Javier

답변:


8

중요한 점은 이미 정의한 것입니다. 하나는 런타임 이고 다른 하나는 컴파일 타임 입니다. 필요한 실제 정보는이 선택의 결과입니다.

컴파일 타임 :

  • 장점 : 컴파일 타임 인터페이스는 런타임 인터페이스보다 훨씬 세분화됩니다. 즉, 호출 할 때 단일 함수 또는 함수 집합의 요구 사항 만 사용할 수 있다는 의미입니다. 항상 전체 인터페이스를 수행 할 필요는 없습니다. 요구 사항은 정확하고 필요한 것입니다.
  • Pro : CRTP와 같은 기술은 암시 적 인터페이스를 사용하여 연산자와 같은 것을 기본 구현할 수 있음을 의미합니다. 런타임 상속으로 그런 일을 할 수는 없습니다.
  • Pro : 암시 적 인터페이스는 런타임 인터페이스보다 "상속"을 작성하고 곱하기 가 훨씬 쉽고 어떤 종류의 바이너리 제한도 적용하지 않습니다. 예를 들어 POD 클래스는 암시 적 인터페이스를 사용할 수 있습니다. virtual암시 적 인터페이스를 가진 상속이나 다른 shenanigan이 필요하지 않습니다 . 큰 이점입니다.
  • 장점 : 컴파일러는 컴파일 타임 인터페이스에 대해 더 많은 최적화를 수행 할 수 있습니다. 또한 추가적인 유형의 안전성으로 인해 코드가 더 안전합니다.
  • 장점 : 최종 객체의 크기 나 정렬을 모르기 때문에 런타임 인터페이스에 값을 입력하는 것은 불가능합니다. 이는 가치 타이핑을 필요로하거나 이익을 얻는 모든 경우에 템플릿으로부터 큰 이점을 얻는다는 것을 의미합니다.
  • 단점 : 템플릿은 컴파일하고 사용하기에 나쁜 역할을하며 컴파일러간에 깔끔하게 이식 될 수 있습니다.
  • 단점 : 템플릿은 런타임에로드 할 수 없으므로 동적 데이터 구조를 표현하는 데 한계가 있습니다.

실행 시간:

  • 장점 : 최종 유형은 런타임까지 결정될 필요가 없습니다. 즉, 템플릿이이를 수행 할 수있는 경우 런타임 상속으로 일부 데이터 구조를 훨씬 쉽게 표현할 수 있습니다. 또한 COM과 같이 C 경계를 넘어 런타임 다형성 유형을 내보낼 수 있습니다.
  • 장점 : 런타임 상속을 지정하고 구현하는 것이 훨씬 쉬우 며 실제로 컴파일러 고유의 동작을 얻지는 못할 것입니다.
  • 단점 : 런타임 상속은 컴파일 타임 상속보다 느릴 수 있습니다.
  • 단점 : 런타임 상속에서 형식 정보가 손실됩니다.
  • 단점 : 런타임 상속은 유연성이 떨어집니다.
  • 단점 : 다중 상속은 나쁜 것입니다.

상대 목록이 주어지면 런타임 상속 의 특정 이점이 필요 하지 않으면 사용하지 마십시오. 템플릿보다 속도가 느리고 유연성이 떨어지며 안전하지 않습니다.

편집 : C ++에서 특히 상속 용도가 있다는 지적이의 가치가 다른 런타임 다형성보다. 예를 들어, typedef를 상속하거나 유형 태그에 사용하거나 CRTP를 사용할 수 있습니다. 그러나 궁극적으로 이러한 기술 (및 기타 기술)은을 사용하여 구현하더라도 실제로 "컴파일 타임"에 속합니다 class X : public Y.


컴파일 타임에 대한 첫 번째 전문가와 관련하여 이것은 내 주요 질문 중 하나와 관련이 있습니다. 명시 적 인터페이스로만 작업하고 싶다는 것을 분명히하고 싶습니까? 즉. '필요한 모든 기능이 있는지 상관하지 않습니다. 클래스 Z에서 상속하지 않으면 아무 것도 원하지 않습니다.' 또한 포인터 / 참조를 사용할 때 런타임 상속이 형식 정보를 잃지 않습니다.
Chris Morris

@ChrisMorris : 아니요. 작동하면 작동하는 것입니다. 누군가 다른 곳에서 정확히 동일한 코드를 작성하게하는 이유는 무엇입니까?
jmoreno

1
@ChrisMorris : 아뇨. X 만 있으면 X를 요구하고 신경 써야하는 캡슐화의 기본 기본 원칙 중 하나입니다. 또한 형식 정보가 손실됩니다. 예를 들어, 이러한 유형의 객체를 스택 할당 할 수 없습니다. 실제 유형으로 템플릿을 인스턴스화 할 수 없습니다. 템플릿 멤버 함수를 호출 할 수 없습니다.
DeadMG

어떤 클래스를 사용하는 클래스 Q가있는 상황은 어떻습니까? Q는 템플릿 매개 변수를 사용하므로 암시 적 인터페이스를 제공하는 클래스는 그렇게 할 것입니다. 클래스 Q는 내부 클래스 (H라고 함)도 Q의 인터페이스를 사용할 것으로 예상합니다. 예를 들어, H 객체가 파괴되면 Q의 일부 함수를 호출해야합니다. 암시 적 인터페이스에는 지정할 수 없습니다. 따라서 템플릿이 실패합니다. 더 명확하게 말하면, 서로 암시적인 인터페이스 이상의 것을 요구하는 밀접하게 연결된 클래스 집합은 템플릿 사용을 방해하는 것 같습니다.
Chris Morris

Con compiletime : 추악한 디버그, 정의를 헤더에
넣어야 함
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.