Man*_*niP 7 c++ compiler-construction micro-optimization compiler-optimization vptr
这个问题不是关于C++语言本身(即不是关于标准),而是关于如何调用编译器来实现虚函数的替代方案.
实现虚函数的一般方案是使用指向指针表的指针.
class Base {
private:
int m;
public:
virtual metha();
};
Run Code Online (Sandbox Code Playgroud)
等价地说C会是这样的
struct Base {
void (**vtable)();
int m;
}
Run Code Online (Sandbox Code Playgroud)
第一个成员通常是指向虚拟函数列表等的指针(应用程序无法控制的内存中的一块区域).在大多数情况下,这会在考虑成员之前花费指针的大小等等.因此在大约4个字节的32位寻址方案中等等.如果在应用程序中创建了40k多态对象的列表,则大约为40k x在任何成员变量等之前4个字节= 160k字节.我也知道这恰好是C++编译中最快和最常见的实现.
我知道多重继承很复杂(尤其是虚拟类,即菱形结构等).
另一种方法是将第一个变量作为vptrs表的索引id(等效于C,如下所示)
struct Base {
char classid; // the classid here is an index into an array of vtables
int m;
}
Run Code Online (Sandbox Code Playgroud)
如果应用程序中的类总数小于255(包括所有可能的模板实例化等),则char足以保存索引,从而减少应用程序中所有多态类的大小(我排除了对齐问题)等).
我的问题是,在GNU C++,LLVM或任何其他编译器中是否有任何切换来执行此操作?或减少多态对象的大小?
编辑:我了解指出的对齐问题.还有一点,如果这是64位系统(假设为64位vptr),每个多态对象成员的成本约为8字节,那么vptr的成本就是内存的50%.这主要涉及大量创建的小型多态,所以我想知道如果不是整个应用程序,这个方案是否至少可以用于特定的虚拟对象.
您的建议很有趣,但如果可执行文件由多个模块组成并在它们之间传递对象,则该建议将不起作用。鉴于它们是单独编译的(例如 DLL),如果一个模块创建一个对象并将其传递给另一个模块,而另一个模块调用虚拟方法 - 它如何知道引用的是哪个表classid
?您将无法添加另一个模块,moduleid
因为这两个模块在编译时可能不知道彼此。所以除非你使用指针,否则我认为这是一个死胡同......