是否有可能衍生出来和" respecialize"具有从特化类型派生的类型的专用类?

时间:2014-06-25 10:28:25

标签: c++ templates inheritance template-specialization derived-class

简化问题

我有以下内容:

class Foo {};
class Bar : public Foo {};

template <class T>
class TemplatedClass   : public T {};
class SpecializedClass : public TemplatedClass<Foo> {};

我需要一个新班级,

class RespecializedClass : public TemplatedClass<Bar> {};

但是这个新类与SpecializedClass完全相同,只是它专注于Bar,这是一个派生自Foo的类。它简单地复制粘贴SpecializedClass,但是我必须维护两个相同的代码行。

有没有办法从RespecializedClass 派生 SpecializedClass,但是还要将模板数据类型专门化为子数据类型?

原始问题(更接近我的实际问题)

我给出了以下类的层次结构:

class X {};

class A {};

template <class T>
class B : public T, public A {};

class C : public B<X> {};

class D : public C {};

我无法触及XABCD背后的任何来源。我只能从中衍生出来并扩展它们。

现在,我从X派生了一个新类 - 将其称为小写x。 (我通常不会在一个设置中使用Xx,但在这种情况下,视觉相似性在这种情况下很有用。)

class x : public X {};

我需要的是一个与D相同但在x而不是X上模板化的类。

当然,我可以简单地复制粘贴CD并将其专门化为x,如下所示:

class c : public B<x> {};
class d : public c {};

但是,只要CD被修改,我就必须维护此代码。

有没有办法做类似

的事情
class d : public D, public B<x> {};

在层次结构中进一步“重新指定”模板的数据类型?

注意

无需阅读本段;事实上,它可能比启发更容易混淆。我需要d x而不是X模板的原因是x和{{1}封装数据库表,并编写X来更新它模板化的任何表。为了更接近事实,我正在使用的基础架构自动生成所有数据库表的封装类。在数据库字典中,可以配置“派生”表,该表继承来自另一个表的所有字段和键,然后使用其他字段和键扩展该表。基础结构不仅自动生成这些“派生”表的封装类,而且实际上将它们表示为各自父类的派生类。所以,实际上我实际上并不是编码 B - 它正在为我自动生成,作为x的子类。我需要的是,现在我可以更精确,是一个所有 X所做的类,但是在数据库表D上运行,而不是{{ 1}}。

3 个答案:

答案 0 :(得分:2)

  

有没有办法从SpecializedClass派生RespecializedClass,但是进一步将模板数据类型专门化为子数据类型?

不。至少,没有您无法触及SpecializedClass实施的约束。 如果你可以更改它,你应该改变它:

旧代码:

template <class T>
class TemplatedClass   : public T {};
class SpecializedClass : public TemplatedClass<Foo> {};

新代码:

template <class T>
class TemplatedClass   : public T {};
template<type Base = Foo> // << HERE
class SpecializedClass : public TemplatedClass<Base> {};

因为你不能这样做,所以你有以下几种可能:

  • 滚动你自己的SpecializedClass:如你所说,将SpecializedClass复制到你自己的专门化中(类似于上面的“新代码”,然后添加:using RespecializedClass = SpecializedClass<Bar>;)。然后,使用新的SpecializedClass维护所有代码(直接称它为RespecializedClass?:))并忽略原始库提供的代码。您必须将原始代码中的修补程序和修补程序传播到您自己的副本中:(

  • 向公司的原始维护人员提出补丁,解释您的具体需求。如果您为Base提供默认模板参数,则公司内的客户端代码可以在不需要任何更改的情况下运行。

答案 1 :(得分:1)

如果您的目标是最大限度地减少代码重复,我认为最简单的方法就是将您的可共享代码编写为模板,而不是干涉您的ORM库继承树。您的模板将能够对他们操作的类型做出所需的假设(界面类似于D)。

现在,关于问题的简化陈述,如果要重新指定的类的方法在TemplatedClass中声明为虚拟,那么从两者手动SpecializedClass派生它不应该是一个问题TemplatedClass<Bar>SpecializedClass,并执行正确的内部管道。否则,您将无法使用RespecializedClass代替SpecializedClass。剩下的解决方案是为这些创建适配器类,并为适配器编写代码,或者使用本文开头的模板化代码解决方案。

答案 2 :(得分:1)

鉴于您的层次结构:

class X {};
class A {};
template <class T> class B : public T, public A {};
class C : public B<X> {};
class D : public C {};

你可以使B的每个子类也成为一个类模板:

template <class T> class CT: public B<T> {};
template <class T> class DT: public C<T> {};

类模板CTDT由您控制,因此您可以为T==x专门设置它们。只是为了测试,定义一些与旧类CD相等的模板别名:

using class CX = C<X>; // equal to your old C
using class DX = D<X>; // equal to your old D

然后你还需要两个typedef来获取你需要的类:

using class Cx = C<x>;
using class Dx = D<x>;