简体   繁体   中英

What is the reason non-member virtual functions are not supported in C++

I am interested to know what the reason is for there to be no non-member virtual functions in C++. Especially considering the fact that it simply increases code layers when you want to achieve it, since you can define a virtual member-function and then call it from a non-member function.

EDIT: Just for reference, you can do that:

struct Base
{
    virtual void say() const
    {
        std::cout << "Base\n";
    }
};

struct Derived : public Base
{
    void say() const final
    {
        std::cout << "Derived\n";
    }
};

void say(Base* obj)
{
    obj->say();
}

say(static_cast<Base*>(new Derived()));

Edit 2: And there are indeed cases where you want virtual polymorphism, since you can have the case below which doesn't work in a similar fashion, since it prints Base whereas if you were to call it with the above code, in a similar fashion it will print Derived. I believe this summarizes the crux of the problem.

void say(Base* obj)
{
    std::cout << "Base\n";
}

void say(Derived* obj)
{
    std::cout << "Derived\n";
}
say(static_cast<Base*>(new Derived()));

A non-member function does not require an implicit this pointer in order to invoke it.

But virtual functions require a this pointer (ie an object instance ) in order for polymorphism to work.

And there's the contradiction: so it's not possible to have a polymorphic non-member function.

When you want to use polymorphism in free functions you basically have two options. Either you overload the function or you call virtual functions:

#include <iostream>

struct base {
    virtual void func() = 0;
};

struct foo : base { void func() { std::cout << "foo\n"; } };
struct bar : base { void func() { std::cout << "bar\n"; } };

void f(foo& f) { f.func(); }
void f(bar& f) { f.func(); }

void g(base& b) { b.func(); }

int main() {
    foo a;
    bar b;
    f(a);
    f(b);
    g(a);
    g(b);
}

Considering that the main difference to member functions is the implicit this parameter, g is actually rather close to what I'd call a "virtual free function". However, other than that there are no virtual non-member functions in C++.

Having virtual non-member functions is technically challenging to compile.

Virtual functions are usually implemented with a vtable. Classes with virtual member functions store a pointer to that vtable, and that vtable has all the requisite functions added to it. When a virtual function is invoked, the exact function to invoke is looked up in the vtable.

Consider this: I'm writing a library in C++. For user convenience, and to reduce compiletimes, the library is distributed as:

  • the header files for the library
  • binary files that provide the implementation of the functions defined in the headers.

So what's the problem?

These binary files will also contain the vtables for any classes with virtual functions within the header files. In order to add virtual functions to a base class, the compiler will have to read and process the binary representation of the library files, modifying the vtables to add the necessary functions.

This would greatly increase the complexity of linking (making the compiler partially responsible for doing so), and it would bloat executable size (any dynamically loaded libraries would have to be statically linked, since the compiler might not have permission to modify their contents).

Are there technical work-arounds?

Yes, although it would require the implementation of the class to be present in the header file, like a template. Alternatively, the new module system could provide a way to implement this feature by forgoing the need to have separate implementation files.

Even then, it would require a lot of work on the part of compiler developers, and there has not been much demand for this feature. The main benefit this feature provides is being able to quickly and easily overload functions for specific derived classes, which itself is considered something of a code smell (since you'd come close to breaking encapsulation - a library writer writing a function that returns a pointer to a base class may want to change which derived class it returns, for example).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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