나는 컴파일 타임 다형성과 런타임 다형성의 실제 한계를 이해한다고 생각합니다. 그러나 명시 적 인터페이스 (런타임 다형성, 즉 가상 함수 및 포인터 / 참조)와 암시 적 인터페이스 (컴파일 타임 다형성, 즉 템플릿)의 개념적 차이점은 무엇입니까 ?
내 생각은 동일한 명시 적 인터페이스를 제공하는 두 개의 객체는 동일한 유형의 객체 (또는 공통 조상을 가져야 함)이어야하지만 동일한 암시 적 인터페이스를 제공하는 두 개의 객체는 동일한 유형의 객체 일 필요는 없으며 암시 적을 제외해야합니다. 둘 다 제공하는 인터페이스는 기능이 매우 다를 수 있습니다.
이것에 대한 생각?
그리고 두 개의 객체가 동일한 암시 적 인터페이스를 제공하는 경우 가상 객체 조회 테이블과 함께 동적 디스패치가 필요하지 않은 기술적 이점 외에도 이러한 객체가 해당 인터페이스를 선언하는 기본 객체에서 상속하지 않는 이유는 무엇입니까? 그것을 명시적인 인터페이스로 만들고 있습니까? 그것을 말하는 또 다른 방법 : 동일한 암시 적 인터페이스를 제공하고 따라서 샘플 템플릿 클래스의 유형으로 사용할 수있는 두 개의 객체가 해당 인터페이스를 명시 적으로 만드는 기본 클래스에서 상속해서는 안되는 경우를 알려주시겠습니까?
관련 게시물 :
- https://stackoverflow.com/a/7264550/635125
- https://stackoverflow.com/a/7264689/635125
- https://stackoverflow.com/a/8009872/635125
이 질문을보다 구체적으로 만드는 예는 다음과 같습니다.
암시 적 인터페이스 :
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 ++ 문제를 해결할 수 있습니다.
- 템플릿 유형이 암시 적 인터페이스를 제공하는 템플릿 클래스
- 명시 적 인터페이스를 제공하는 기본 클래스 포인터를 사용하는 템플릿이 아닌 클래스
변경되지 않는 코드 :
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은, 다른 한편으로는, 소요됩니다 어떤 이 클래스 기능을.CoolClass
worthless()
doSomethingCool()
코드 사용자가 항상 훌륭한 서브 클래 싱 CoolClass
이라면 사례 1은 CoolClassUser
항상의 구현을 기대하기 때문에 직관적 인 의미 가 있습니다 CoolClass
. 그러나이 코드가 API 프레임 워크의 일부라고 가정하면 사용자가 함수 CoolClass
가있는 자체 클래스 를 서브 클래스 화 하거나 롤링 할지 여부를 예측할 수 없습니다 doSomethingCool()
.