Defining and overriding methods of an abstract base class which must accept a template parameter

Jonathan M Davis via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Jul 10 16:57:58 PDT 2016


On Sunday, July 10, 2016 21:27:14 pineapple via Digitalmars-d-learn wrote:
> On Sunday, 10 July 2016 at 21:20:34 UTC, Basile B. wrote:
> > The problem you encounter here is that templatized functions
> > cannot be virtual. If you remove "abstract" and put an empty
> > body than it works, but you lose the whole OOP thing, i.e you
> > cannot call the most derived override from the base.
>
> Yeah, that was the first thing I tried, and it took me a while
> and some measure of annoyance to realize the base method was
> being called instead of the derived one.
>
> Surely there's some reasonable workaround?

You can have an abstract non-templated function which then calls a templated
function in the derived class' implementation, and you can have a templated
function in the base class which then calls an abstract, non-templated
function that the derived class implements. But if you actually need the
templated function to be virtual, then there is no way to do it.

For instance, overloaded operators usually can't be virtual in D, because
most of them are templated. However, a workaround for them is to declare the
overloaded operator on the base class and then have it call a non-templated
function which the derived classes override. e.g. a typical opBinary would
look something like

class C
{
    C opBinary(string op)(C rhs)
        if(["+, "-", "*", "-"].canFind(op))
    {
        mixin("return this.value " ~ op ~ " rhs.value;");
    }

    int value;
}

but that can't be virtual. So, you if you need virtual, overloaded
operators, then you do something like

class C
{
    C opBinary(string op)(C rhs)
        if(op == "=")
    {
        return doAdd(rhs);
    }

    C opBinary(string op)(C rhs)
        if(op == "-")
    {
        return doSub(rhs);
    }

    C opBinary(string op)(C rhs)
        if(op == "*")
    {
        return doMul(rhs);
    }

    C opBinary(string op)(C rhs)
        if(op == "/")
    {
        return doDiv(rhs);
    }

    protected abstract C doAdd(C c);
    protected abstract C doSub(C c);
    protected abstract C doMul(C c);
    protected abstract C doDiv(C c);

    int value;
}

But that only works, because you're not really dealing with an arbitrary
list of possible, template arguments. If you really need it to work with a
list of unknown, possible, template arguments, then you're out of luck.

The only way that you're going to get what you're trying to do to work is if
you can find a way to define a non-templated function (or set of functions)
that can be virtual and do the work that you need to be virtual.

- Jonathan M Davis



More information about the Digitalmars-d-learn mailing list