在以下示例中,使用隐式接口(情况2和3;模板)与使用显式接口(情况1;指向抽象类的指针)有何优缺点?
不需要更改的代码:
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()
{
CoolClass * c1 = new CoolA;
CoolClass * c2 = new CoolB;
CoolClassUser user;
user.useCoolClass(c1);
user.useCoolClass(c2);
return 0;
}
情况二:模板类的模板类型提供隐式接口:
template <typename T>
class CoolClassUser
{
public:
void useCoolClass(T * coolClass)
{ coolClass->doSomethingCool(); }
};
int main()
{
CoolClass * c1 = new CoolA;
CoolClass * c2 = new CoolB;
CoolClassUser<CoolClass> user;
user.useCoolClass(c1);
user.useCoolClass(c2);
return 0;
}
第三种情况:一个模板类,其模板类型提供了一个隐式接口(这次不是从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()函数的类。
一些相关的帖子: https://dev59.com/62w05IYBdhLWcg3wZA8C#7264550 https://dev59.com/62w05IYBdhLWcg3wZA8C#7264689 https://dev59.com/amsz5IYBdhLWcg3wR1oc#8009872