Thread overview
C++ linkage specifics WRT virtual vs non-virtual member functions
Aug 13, 2017
Roman Hargrave
Aug 13, 2017
Timon Gehr
August 13, 2017
I'm writing some bindings and have run in to a dilemma due to the lack of explicit information on how the D compiler "decides" to use virtual dispatch for a member function or not.

Specifically, I have a C++ library that _explicitly_ marks some member functions as virtual, in addition to a plethora of non-virtual functions.

I would like to be certain that the D compiler understands that I would like it to treat those functions as virtual functions, but unlike C++ where there is a `virtual` classifier for functions, D does not appear to have such a facility.

The C++ interop documentation suggests that both non- and virtual functions are supported, but further suggests that it only treats inherited functions as virtual with no method of explicitly requesting virtual dispatch for that method.

As far as I can tell, all specified member functions in a class with C++ linkage are assumed to be non-virtual unless they are overriden?
August 13, 2017
On Sunday, 13 August 2017 at 07:18:31 UTC, Roman Hargrave wrote:
> I'm writing some bindings and have run in to a dilemma due to the lack of explicit information on how the D compiler "decides" to use virtual dispatch for a member function or not.
>
> Specifically, I have a C++ library that _explicitly_ marks some member functions as virtual, in addition to a plethora of non-virtual functions.
>
> I would like to be certain that the D compiler understands that I would like it to treat those functions as virtual functions, but unlike C++ where there is a `virtual` classifier for functions, D does not appear to have such a facility.
>
> The C++ interop documentation suggests that both non- and virtual functions are supported, but further suggests that it only treats inherited functions as virtual with no method of explicitly requesting virtual dispatch for that method.
>
> As far as I can tell, all specified member functions in a class with C++ linkage are assumed to be non-virtual unless they are overriden?

W.r.t. virtual member functions, D's syntax is more similar to Java than to C++, in that class member functions are virtual by default, unless marked as `final`.
So to declare the following C++ class:

class Base
{
    virtual int fun();
    int gun();
};

In D you have to do the following:

extern (C++) class Base
{
    int fun();
    final int gun();
}

Like all other attributes, you can group multiple members to which you want to apply the `final` attribute by either:

class C
{
    final
    {
        int gun();
        int hun();
    }
}

Or:

class C
{
    final:

    int gun();
    int hun();
}

Though be aware that unlike the protection attributes (public, private), there's no way to undo 'final:', so if you use it, you would have to move it with all the non-virtual methods to the bottom of the class definition.
August 13, 2017
On 13.08.2017 09:18, Roman Hargrave wrote:
> I'm writing some bindings and have run in to a dilemma due to the lack of explicit information on how the D compiler "decides" to use virtual dispatch for a member function or not.
> 
> Specifically, I have a C++ library that _explicitly_ marks some member functions as virtual, in addition to a plethora of non-virtual functions.
> 
> I would like to be certain that the D compiler understands that I would like it to treat those functions as virtual functions, but unlike C++ where there is a `virtual` classifier for functions, D does not appear to have such a facility.
> ...

You can create one (this will look nicer with static foreach):

struct virtual{}
mixin template CheckVirtual(T){
    import std.traits: isFinal, hasUDA;
    mixin({string r="";
    foreach(m;__traits(allMembers,T)){
        r~=`static assert(isFinal!(T.`~m~`)||hasUDA!(T.`~m~`,virtual),"'`~T.stringof~`.`~m~`' is neither final nor @virtual");`;
        r~=`static assert(!isFinal!(T.`~m~`)||!hasUDA!(T.`~m~`,virtual),"'`~T.stringof~`.`~m~`' is both final and @virtual");`;
    }
    return r;}());
}

// example:
extern(C++) class C{
    final void foo(){} // ok
    @virtual void bar(){} // ok
    void baz(){} // Error: static assert  "'C.baz' is neither final not @virtual"
    @virtual final void qux(){} // Error: static assert  "'C.qux' is both final and @virtual"
}
mixin CheckVirtual!C;



> The C++ interop documentation suggests that both non- and virtual functions are supported, but further suggests that it only treats inherited functions as virtual with no method of explicitly requesting virtual dispatch for that method.
> 
> As far as I can tell, all specified member functions in a class with C++ linkage are assumed to be non-virtual unless they are overriden?

All member functions are virtual by default. Only member functions explicitly marked as `final` are not virtual. The code above makes both explicit to help prevent mistakes.