简体   繁体   English

C++:模板类的部分实现

[英]C++: partial implementation of a template class

Suppose I have a hierarchy of two classes:假设我有两个类的层次结构:

class Base {
public:
    virtual ~Base() {}
    virtual int next(int x) const { return x+1; }
};

class Derived: public Base {
public:
    virtual int prev(int x) const { return x-1; }
};

I want to create a Modifier class template that could apply to both Base and Derived and changes the behaviour of next() (if used with Base ) or both next() and prev() (if used with Derived ).我想创建一个可以同时应用于BaseDerivedModifier类模板,并更改next() (如果与Base一起使用)或 next() 和prev() (如果与Derived一起使用)的行为。 Here is an inelegant solution with code duplication:这是一个带有代码重复的不雅解决方案:

template<class BaseOrDerived> class Modifier;

template<> class Modifier<Base>: public Base {
    const Base& obj;
    const int k;
public:
    Modifier(const Base& _obj, int _k) : obj(_obj), k(_k) {}
    virtual int next(int x) const { return obj.next(x)+k; }
};

template<> class Modifier<Derived>: public Derived {
    const Derived& obj;
    const int k;
public:
    Modifier(const Derived& _obj, int _k) : obj(_obj), k(_k) {}
    virtual int next(int x) const { return obj.next(x)+k; }
    virtual int prev(int x) const { return obj.prev(x)-k; }
};

Now the question: how to do this better?现在的问题是:如何更好地做到这一点? Can I write down the first specialization Modifier<Base> in full (or write it in a general form without any template specialization), and then somehow "add" the method prev() to a specialization of the template class Modifier<Derived> ?我可以完整地写下第一个特化Modifier<Base> (或以没有任何模板特化的通用形式编写它),然后以某种方式将方法prev() “添加”到模板类Modifier<Derived>的特化中吗?

I tried to do this by making Modifier<Derived> inherit from both Derived and Modifier<Base> and using a virtual inheritance, but this results in a rather ugly diamond inheritance diagram, with duplicated obj member variables of two different types, and is not really what I want: the two template specializations do not need to inherit from one another, they just need to implement the same behaviour for next() .我试图通过使Modifier<Derived>DerivedModifier<Base>继承并使用虚拟继承来做到这一点,但这会导致一个相当难看的菱形继承图,其中包含两种不同类型的重复obj成员变量,并且不是真的是我想要的:这两个模板特化不需要相互继承,它们只需要为next()实现相同的行为。

Thanks in advance for any suggestions.在此先感谢您的任何建议。

This all sounds a bit too tricksy for me - I would just make k a member of Base and have done with it - but if you really want to do it this way then simple template inheritance (aka static polymorphism) will do the job.这一切对我来说听起来有点太棘手了——我只会让k成为Base的成员并完成它——但如果你真的想这样做,那么简单的模板继承(又名静态多态性)就可以完成这项工作。

So what I have done here is structured the Modifier templates into a class hierarchy and done away with them inheriting from the actual classes whose behaviour they are modifying, since that is what is messing you up.所以我在这里所做的是将修饰符模板结构化为一个类层次结构,并取消它们从它们正在修改其行为的实际类继承,因为这会让你感到困惑。 And when you do that, this is what you end up with:当你这样做时,这就是你最终的结果:

template<class BaseOrDerived> class Modifier;

template<class BaseOrDerived> class ModifierCommon{
    friend class Modifier<Derived>;
    const BaseOrDerived& obj;
    const int k;
public:
    ModifierCommon(const BaseOrDerived& _obj, int _k) : obj(_obj), k(_k) {}
    virtual int next(int x) const { return obj.next(x)+k; }
};

template<> class Modifier<Base>: public ModifierCommon<Base> {
    using ModifierCommon<Base>::ModifierCommon;
};

template<> class Modifier<Derived>: public ModifierCommon<Derived> {
    using ModifierCommon<Derived>::ModifierCommon;
public:
    virtual int prev(int x) const { return obj.prev(x)-k; }
};

And that's all there is to it, best of luck.这就是它的全部内容,祝你好运。 But, as I say, personally I wouldn't do it at all, you're just over-egging the pudding.但是,正如我所说,就我个人而言,我根本不会这样做,你只是把布丁炒得过火了。

Demo演示


Hokay, as per the comments the OP has moved the goalposts a bit so let's see what we can do.好吧,根据评论,OP已经稍微移动了球门柱,所以让我们看看我们能做些什么。

To be able to access, for example, Modifier<Base> as if (more or less) it was a true Base object, you can add a couple of tweaks to the ModifierCommon template as follows:例如,为了能够访问Modifier<Base> ,就好像(或多或少)它是一个真正的Base对象一样,您可以向ModifierCommon模板添加一些调整,如下所示:

template<class BaseOrDerived> class ModifierCommon{
...
public:
    // Add these
    BaseOrDerived* operator->() { return &this->obj; }
    const BaseOrDerived* operator->() const { return &this->obj; }
    operator BaseOrDerived& () const { return this->obj; }
    // End add these
...
};

So, after taking out a couple of const s, the whole thing now becomes:所以,在取出几个const之后,整个事情现在变成了:

template<class BaseOrDerived> class ModifierCommon{
    friend class Modifier<Derived>;
    BaseOrDerived& obj;
    const int k;
public:
    ModifierCommon(BaseOrDerived& _obj, int _k) : obj(_obj), k(_k) {}
    BaseOrDerived* operator->() { return &this->obj; }
    const BaseOrDerived* operator->() const { return &this->obj; }
    operator BaseOrDerived& () const { return this->obj; }
    virtual int next(int x) const { return obj.next(x)+k; }
};

And here's an example of how you might use it (I added a test method called foo to Base and another called bar to Derived ):下面是一个如何使用它的示例(我在Base中添加了一个名为foo的测试方法,在Derived中添加了另一个名为bar的测试方法):

void call_me_using_base (Base &b) { }
void call_me_using_derived (Derived &d) { }

int main()
{
    Base b;
    std::cout << b.next (100) << "\n";
    Modifier<Base> mb (b, 42);
    std::cout << mb.next (100) << "\n";
    std::cout << mb->foo (10) << "\n";
    call_me_using_base (mb);

    Derived d;
    std::cout << d.next (100) << "\n";
    std::cout << d.next (100) << "\n";
    Modifier<Derived> md (d, 84);
    std::cout << md.next (100) << "\n";
    std::cout << md.prev (100) << "\n";
    std::cout << md->bar (21) << "\n";
    call_me_using_derived (md);
}

Updated demo更新的演示

And no, I still wouldn't do this.不,我仍然不会这样做。 Design a proper class hierarchy like everybody else does.像其他人一样设计一个适当的类层次结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM