我可以使用转换构造函数来处理模板参数中的继承链吗?

时间:2012-09-07 19:50:57

标签: c++ templates inheritance

假设我class D继承自class B。我有一个模板类template <class T> C。然后我有一个函数签名void foo(C<B> c);。为了使C实例使用来自B的派生类进行模板化,我是否需要提供转换构造函数?像template <class DERIVED> C(const C<DERIVED>& c) {}这样的东西?这对于C中发生的任何其他内容是否足够,因为任何D都是B

1 个答案:

答案 0 :(得分:2)

C<D>C<B>根本不是相关类型,所以是的,您必须提供允许C<B>C<D>构建的转化}。

这可能不会使类型完全兼容。例如,函数void foo(C<B> &c)将无法使用该转换。

这些不相关的类型是否可以与您的使用相匹配,取决于您在兼容性方面如何定义类型以及您需要的类型。


struct B {};
struct D : B {};

template<typename T>
struct C {};

int main() {
    C<B> c = C<D>();
}

test1.cpp:9:10: error: no viable conversion from 'C<struct D>' to 'C<struct B>'
    C<B> c = C<D>();
         ^   ~~~~~~

考虑这个例子,说明为什么模板的不同专业化之间不应该存在任何关系:

struct B {};
struct D : B {};

template<typename T> struct C;

template<> struct C<B> { int i; }; // different specializations
template<> struct C<D> { double a, b, c; }; // can have different definitions

在继承相关的类型之间进行转换是有效的,因为派生类型始终具有基类型的子对象。即便如此,必须仔细设计使用继承的类型才能正常工作。


用户定义的转换通过非显式构造函数和类型运算符进行操作:

struct T {};

struct S {
    S() {}
    S(T const &) {}
    operator T () { return T(); }
};

void foo(T t) {}
void bar(S s) {}

int main() {
    foo(S()); // uses S::operator T ()
    bar(T()); // uses S::S(T const &)
}

您可以在标准 12.3.2转换函数[class.conv.fct] 中阅读更多内容以及它们如何在重载决策中使用 13.3重载分辨率[over.match] < / em>的