虚函数调用的优化

时间:2012-09-22 12:42:15

标签: c++ optimization virtual-functions vtable

我对优化虚拟函数调用有疑问。我已经阅读了某个地方(问题是我现在找不到文章),可以通过使用类似于此的构造来优化掉v-table查找:

// Base.h
class Base
{
public:
    virtual void Foo() = 0;
};

// Concrete.h
class Concrete : public Base
{
public:
    virtual void Foo()
    {
        // do something;
    }
};

//Some.h
extern Base* const g_object;

// Some.cpp
Concrete on_stack_concrete;

Base* const g_object = &on_stack_concrete;

这个技巧应该是使用一个const指针指向在堆栈上分配的变量(不是动态的),并且编译器肯定会优化它。因此,无论何时用户调用g_object-> Foo(),//都会执行某些部分,而无需进行v-table查找。

这是真的吗?

提前感谢任何重播。

编辑:

此类构造的可能用法是限制具体实现的接口。当然,人们可以争辩说“受限制”的方法应该是私有的,但有时库的其他模块需要访问对象的那些公共附加方法而不允许用户操纵它们。因此,例如使用#defines,可以创建类似于:

的代码
// Some.cpp
#ifdef _WIN32
Win32Concrete concrete;
#elif defined _UNIX
UnixConcrete concrete;
#endif

Base* const g_global = &concrete;

实际上,这些类的声明只能在CPP文件中定义,因此用户不知道它们的存在。

问题不是为什么首先使用这样的常量指针,但是如果可以在这种情况下优化掉v表查找。

3 个答案:

答案 0 :(得分:4)

您似乎在滥用virtual

virtual实现了运行时多态性。您描述的场景不使用或不需要。在任何编译环境中都不可能存在Win32ConcreteUnixConcrete

而不是:

// Some.cpp
#ifdef _WIN32
Win32Concrete concrete;
#elif defined _UNIX
UnixConcrete concrete;
#endif

Base* const g_global = &concrete;

使用:

// CommonHeader.h
#ifdef _WIN32
typedef Win32Concrete Concrete;
#elif defined _UNIX
typedef UnixConcrete Concrete;
#endif

现在你的功能不需要是虚拟的。

答案 1 :(得分:1)

解决此问题的最简单方法是使需要访问Concrete类的受限方法朋友的类。然后他们就可以完全访问该课程,其他人只能获得公共访问权。

如果这不可行,可以将实现放在基类中,并保护所有受限制的方法,然后派生一个公开受保护方法的特殊类。

class Concrete
{
public:
    void foo() { ... }
protected:
    void bar() { ... }
};

class ConcretePrivate : public Concrete
{
public:
    void bar() { Concrete:: bar(); }
};

ConcretePrivate g_globalPrivate;
Concrete& g_global = g_globalPrivate;

使用g_global的代码只能访问Concrete方法。使用g_globalPrivate的代码可以访问ConcretePrivate方法。

答案 2 :(得分:1)

这是Doom 3源代码(https://github.com/id-Software/DOOM-3-BFG/)中使用的方法,例如neo / framework / FileSystem.h定义了这个:

extern idFileSystem *       fileSystem;

neo / framework / FileSystem.cpp定义了这个:

idFileSystemLocal   fileSystemLocal;
idFileSystem *      fileSystem = &fileSystemLocal;

我能找到的唯一讨论是:http://fabiensanglard.net/doom3/

  

idTech4高级对象都是带有虚方法的抽象类。这通常会涉及性能损失,因为在运行时调用它之前必须在vtable中查找每个虚拟方法地址。但是有一个"技巧"为了避免这种情况。

     

由于在数据段中静态分配的对象具有已知类型,因此编译器可以在调用commonLocal方法时优化vtable查找。