C++中的继承和模板

Inheritance and templates in C++

本文关键字:继承 C++      更新时间:2023-10-16

我在继承和模板方面有以下问题:

class Base {};
class Deriv : public Base {};
template <class T> class X{};
void f(X<Base>& inst) {}
int main()
{
  X<Base> xb;
  f(xb);
  X<Deriv> xd;
  f(xd);
  return 0;
}

程序无法编译,因为X<Base>X<Deriv>之间没有关系。尽管如此,我认为应该可以做所有可以用X<Base>也可以用X<Deriv>做的事。除了将f的函数体复制到新的函数void g(X<Deriv>& inst)之外,我还能做些什么吗?

您可以继续使用模板:

template<class T>
void f(X<T>& inst) {}

将适用于X<Base>X<Derived>.

编译器可能会复制代码(如果它不够智能),但您不必这样做。

为什么你认为它们应该相关?请考虑以下事项:

template<typename T>
class X;
template<>
class X<Base> {
    int x;
};
template<>
class X<Deriv> {
    double d;
};

它们绝对不能互换。所以不,这些类之间没有关系,你不能将一个传递给期望另一个的函数。您必须执行一些操作,例如使这两种类型都继承自公开所需接口的另一个通用类型。

<小时 />

关于你的评论,你可以使用类型特征和static_assert来做你在 Java 中会做的事情:

template<typename T>
void f(X<T>& inst) {
    static_assert(std::is_base_of(Base, T)::value, "Template type must subclass Base");
    // body of function...
}

如果您需要这样的功能,那么您必须在类型或重载上进行模板化,正如您所说。或者,您可以显式专用化X以便X<Derived> : X<Base> .

模板的不同实例化是不相关的类型,即使实例化模板参数是相关的。也就是说,无论AB之间的关系如何,X<A>都与X<B>无关。

现在至于可以做什么,这取决于您的模板实际上是什么。 在某些情况下,您可以提供转换,以便可以将X<Derived>转换为特定操作的X<Base>。另一种选择是修改您的函数,以便能够接受T派生自Base的任何X<T>(这可以通过创建模板并使用 SFINAE 禁止使用非派生自BaseT 调用它来完成。同样,根据模板是什么,您可能能够提供对基础类型的访问,在这种情况下,函数可以引用Base(考虑使用 .get() 方法shared_ptrunique_ptr

如果没有描述你真正想要完成的事情,就不可能提供一个好的选择。

这取决于。考虑X std::shared_ptr的情况。如果std::shared_ptr<Derived>是从std::shared_ptr<Base>派生的,则会破坏类型安全,而是存在隐式值转换。

但是,由于您是通过引用非const传递的,因此这样的值转换不会直接帮助您。

其他可能性包括从公共接口继承和模板化函数。