C++不支持非成员虚拟功能的原因是什么?
What is the reason non-member virtual functions are not supported in C++
我很想知道C++中没有非成员虚函数的原因是什么。特别是考虑到它只是在你想要实现它时增加代码层,因为你可以定义一个虚拟成员函数,然后从非成员函数调用它。
编辑: 仅供参考,您可以这样做:
struct Base
{
virtual void say() const
{
std::cout << "Basen";
}
};
struct Derived : public Base
{
void say() const final
{
std::cout << "Derivedn";
}
};
void say(Base* obj)
{
obj->say();
}
say(static_cast<Base*>(new Derived()));
编辑 2: 确实存在你想要虚拟多态性的情况,因为你可以有下面的情况,它不能以类似的方式工作,因为它打印 Base,而如果你用上面的代码调用它,它会以类似的方式打印派生。我认为这总结了问题的症结。
void say(Base* obj)
{
std::cout << "Basen";
}
void say(Derived* obj)
{
std::cout << "Derivedn";
}
say(static_cast<Base*>(new Derived()));
非成员函数不需要隐式this
指针即可调用它。
但是虚函数需要一个this
指针(即对象实例)才能使多态性起作用。
还有一个矛盾:所以不可能有一个多态的非成员函数。
拥有虚拟的非成员函数在技术上很难编译。
虚拟函数通常通过 vtable 实现。具有虚拟成员函数的类存储指向该 vtable 的指针,并且该 vtable 添加了所有必需的函数。调用虚拟函数时,将在 vtable 中查找要调用的确切函数。
考虑一下:我正在用C++编写一个库。为了方便用户并减少编译时间,该库分布为:
- 库的头文件
- 提供标头中定义的函数的实现的二进制文件。
那么问题出在哪里呢?
这些二进制文件还将包含头文件中具有虚函数的任何类的 vtables。为了将虚函数添加到基类,编译器必须读取和处理库文件的二进制表示形式,修改 vtables 以添加必要的函数。
这将大大增加链接的复杂性(使编译器部分负责这样做),并且会膨胀可执行文件的大小(任何动态加载的库都必须静态链接,因为编译器可能没有修改其内容的权限)。
是否有技术解决方法?
是的,尽管它要求类的实现存在于头文件中,就像模板一样。或者,新的模块系统可以通过放弃单独的实现文件来提供一种实现此功能的方法。
即便如此,编译器开发人员也需要做大量工作,并且对此功能的需求并不大。此功能提供的主要好处是能够快速轻松地重载特定派生类的函数,这本身被认为是一种代码气味(因为你几乎要破坏封装 - 编写返回指向基类的指针的函数的库编写器可能想要更改它返回的派生类, 例如)。
当你想在自由函数中使用多态性时,你基本上有两个选择。要么重载函数,要么调用虚函数:
#include <iostream>
struct base {
virtual void func() = 0;
};
struct foo : base { void func() { std::cout << "foon"; } };
struct bar : base { void func() { std::cout << "barn"; } };
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);
}
考虑到与成员函数的主要区别在于隐式this
参数,g
实际上非常接近我所说的"虚拟自由函数"。但是,除此之外,C++中没有虚拟的非成员功能。
- 文件系统:复制功能的速度秘诀是什么
- c++20[[no.unique_address]]中的新功能是什么
- 这个Arduino睡眠设置的周边是什么警报功能?
- 这种错误的原因是什么:将"功能"重新定义为不同类型的符号
- 关键字使用的功能是什么?
- 引用 using 声明引入的功能的句子是什么意思?
- 共享_ptr中多功能数组的类型是什么
- 为什么BOOST :: HANA :: EXAREMIS ::键入实验功能?类型列表的棘手是什么
- 不允许功能模板的部分专业化背后的理由是什么?
- 在 C++ 中直接为 FOR 循环提供的 " ; " 的功能是什么?
- C++不支持非成员虚拟功能的原因是什么?
- 是什么导致程序在我继续执行另一个功能之前停止
- & 字符在重载 std::cout 中的功能是什么?
- 当我运行此C 程序时,该功能是什么
- 在 LLVM 中,调用中函数的位播"type"是什么?如何访问此功能?
- 导出()在QMake中的"inverse"功能是什么?
- 在Linux上构建具有链接时代码生成功能的静态库的正确方法是什么
- 通过回调功能,打破一个循环的最佳方法是什么?
- 该功能检测循环链接列表的时间复杂性是什么?
- 对于一对碰撞机会较低的INT的最小哈希功能是什么