我想我了解编译时多态和运行时多态的实际限制。但是显式接口(运行时多态,即虚拟函数和指针/引用)与隐式接口(编译时多态,即模板)之间在概念上有什么区别。
我的想法是,提供相同显式接口的两个对象必须是相同类型的对象(或具有共同的祖先),而提供相同隐式接口的两个对象不必是相同类型的对象,并且不包括隐式对象他们俩都提供的接口可以具有完全不同的功能。
有什么想法吗?
并且,如果两个对象提供相同的隐式接口,那么还有什么原因(除了不需要动态分配带有虚拟函数查找表的技术好处等)之外,还有其他原因导致这些对象不能从声明该接口的基础对象继承而来。使它成为显式接口?换一种说法:您能给我一个例子吗,两个提供相同隐式接口的对象(因此可以用作示例模板类的类型)不应从使该接口显式的基类继承?
一些相关的帖子:
- 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()
是一个孩子CoolClass
(和执行worthless()
)。另一方面,情况2和3将采用任何具有doSomethingCool()
函数的类。
如果代码的用户始终是很好的子类CoolClass
,则案例1具有直觉的意义,因为CoolClassUser
始终希望的实现CoolClass
。但是假设此代码将成为API框架的一部分,因此我无法预测用户是否要继承CoolClass
或滚动自己的具有doSomethingCool()
功能的类。