简体   繁体   English

C ++不支持非成员虚拟函数的原因是什么

[英]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++. 我很想知道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. 编辑2:确实确实有一些情况需要虚拟多态性,因为下面的情况不能以类似的方式工作,因为它会打印Base,而如果要用上述代码调用它,则类似它将打印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. 非成员函数不需要隐式this指针即可调用它。

But virtual functions require a this pointer (ie an object instance ) in order for polymorphism to work. 但是虚函数需要this指针(即对象实例 )才能使多态性起作用。

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". 考虑到与成员函数的主要区别是隐式的this参数,因此g实际上非常接近于我所谓的“虚拟自由函数”。 However, other than that there are no virtual non-member functions in C++. 但是,除此之外,C ++中没有虚拟的非成员函数。

Having virtual non-member functions is technically challenging to compile. 具有虚拟非成员函数在编译时在技术上具有挑战性。

Virtual functions are usually implemented with a vtable. 虚函数通常用vtable实现。 Classes with virtual member functions store a pointer to that vtable, and that vtable has all the requisite functions added to it. 具有虚拟成员函数的类存储指向该vtable的指针,并且该vtable已添加了所有必需的函数。 When a virtual function is invoked, the exact function to invoke is looked up in the vtable. 调用虚拟函数时,将在vtable中查找要调用的确切函数。

Consider this: I'm writing a library in C++. 考虑一下:我正在用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. 这些二进制文件还将在头文件中包含具有虚函数的任何类的vtable。 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. 为了将虚拟函数添加到基类,编译器将必须读取和处理库文件的二进制表示,并修改vtable以添加必要的函数。

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). 此功能提供的主要好处是能够快速轻松地为特定的派生类重载函数,该派生类本身被认为是某种代码味道(因为您接近破坏封装的作用-库编写器编写了返回指针的函数例如,对基类的更改可能想要更改它返回的派生类)。

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

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