Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 手动使用多种类型比多态更快?_C++ - Fatal编程技术网

C++ 手动使用多种类型比多态更快?

C++ 手动使用多种类型比多态更快?,c++,C++,我需要制作一个要渲染的对象列表。。。现在我开始思考,不管风格或个人偏好,只考虑性能,还有什么选择更快 多类型/开关语句: void Object::Render() { switch(type) { case BUTTON: RenderButton(this); break; case NOT_BUTTON: RenderNotButton(this);

我需要制作一个要渲染的对象列表。。。现在我开始思考,不管风格或个人偏好,只考虑性能,还有什么选择更快

多类型/开关语句:

void Object::Render()
{
    switch(type)
    {
        case BUTTON:
            RenderButton(this);
            break;
        case NOT_BUTTON:
            RenderNotButton(this);
            break;
        case WIDGET_ABC:
            RenderWidgetAbc(this);
            break;
    }
}
或多态性:

virtual void Object::Render();

class Button : public Object
{
     void Render();
}
编辑1:如果有帮助的话,我要说的是,它将在ARMV6设备中运行

编辑2:当前项目上有零对象(项目目标的一部分是用C++以更为有效的编程方式进行实验),这就是为什么要考虑这个问题。 此外,这将是代码中调用频率最高的部分,如果它是作为switch语句实现的,那么不会调用其他方法,因此它确实是性能关键的


编辑3:这部分代码实际上是处理要转储到GPU的顶点和UV列表,GPU比CPU快,我想以尽可能快的速度抛出顶点和UV。渲染不受CPU限制。此外,它将有多边形对象,而不仅仅是像GUI这样的简单操作系统。

我认为性能差异将足够小,因此可以忽略它。然而,可维护性、可测试性和设计将受到很大影响,因此我不会使用第一个版本


我的经验表明,每次我试图用如此小的优化比编译器更聪明时,我最终的结果是主机实际上变小了。

您的第一个代码是维护和设计的噩梦。考虑一下当你需要添加新类型时的情况

至于表演。只有分析才能为您各自的平台和环境提供明确的答案。

带有开关的版本应该更快,因为多态性要求将对象移动到缓存中,但这实际上是一个微观优化


我会选择多态性,因为代码可以设计得更好。

你说的更快是什么意思

使用多态性会更快,因为

  • 这样会更好
  • 可维护性当然更好(因此对您来说更快,这一点很重要)
  • 它允许以简单的方式进行更复杂的设计
仅仅从性能的角度来看,多态性的实现是通过一个查找表完成的,需要的是一个双间接引用来获取动态调用方法的地址这意味着多态性的时间是恒定的,即使它不是微不足道的,因为该方法无法加载到缓存中


使用开关调用适当的方法只是忘记了OOP。这样做毫无意义。仅仅因为缓存命中/未命中,它的速度可能会加快一些CPU周期,但几乎从来都不值得这样做。

我运行了以下代码来比较这两者。正如我预期的那样,虚拟函数稍微快一点(我将在下面解释原因)

然后我添加了-02(用于优化)进行构建,结果如下

Virtual Function
Elapsed time 132 milliseconds
button counter = 10000000
notButton counter = 20000000
widgetAbc counter = 30000000
Switch Function
Elapsed time 206 milliseconds
button counter = 20000000
notButton counter = 40000000
widgetAbc counter = 60000000
Virtual Function
Elapsed time 58 milliseconds
button counter = 10000000
notButton counter = 20000000
widgetAbc counter = 30000000
Switch Function
Elapsed time 76 milliseconds
button counter = 20000000
notButton counter = 40000000
widgetAbc counter = 60000000
在这两种情况下,虚拟功能都更快

虽然虚拟函数比非虚拟函数慢,但开销最小。虚拟函数最有可能是函数指针(尽管编译器可以以不同的方式执行)。因此,当调用虚函数时,唯一额外的开销是指针解引用。下面是一个编译器可以为虚拟调用执行的操作的示例。编译器可以做得更优雅一点,但你可以得到这个想法

#include <stdio.h>

class Object
{
    public:
        // function pointer acting as virtual function call
        void (*funcPtr) (void *this_ptr);
};

class Button : public Object
{
    public:
        Button();
        static void virtualFunc(void *this_ptr);

        int counter;
};

Button::Button()
    :counter(0)
{
    // set object function pointer to our "virtual function"
    funcPtr = &Button::virtualFunc;
}

void Button::virtualFunc(void *this_ptr)
{
    Button *button_ptr = reinterpret_cast<Button*>(this_ptr);
    button_ptr->counter++;
}

int main()
{
    Object *button = new Button();

    // virtual call using a function pointer
    button->funcPtr(button);

    printf("button counter = %d\n", static_cast<Button*>(button)->counter);

    return 0;
}
#包括
类对象
{
公众:
//充当虚拟函数调用的函数指针
作废(*funcPtr)(作废*本文件);
};
类按钮:公共对象
{
公众:
按钮();
静态void virtualFunc(void*this_ptr);
整数计数器;
};
按钮::按钮()
:计数器(0)
{
//将对象函数指针设置为“虚拟函数”
funcPtr=&按钮::virtualFunc;
}
void按钮::virtualFunc(void*此ptr)
{
Button*Button_ptr=重新解释(此_ptr);
按钮->计数器++;
}
int main()
{
对象*按钮=新按钮();
//使用函数指针的虚拟调用
按钮->功能(按钮);
printf(“按钮计数器=%d\n”,静态(按钮)->计数器);
返回0;
}

您为什么要关心哪个更快?您忽略了其他因素,比如可扩展性。速度确实是最不重要的问题,至少在您测量并确认部分代码是热点之前。对于在用户界面中呈现按钮(屏幕上可以容纳多少个按钮?100?),任何可能的性能差异都可以忽略不计。@us2012对于呈现任何内容,与实际渲染的成本相比,虚拟函数调用的成本是无法衡量的。@JamesKanze视情况而定。在处理和渲染成千上万的3D对象(基本体)时,就像在许多(尽管不是全部)视频游戏中一样,每个对象的虚拟函数调用可能是可测量的——更重要的是,它指示了更具象征意义的剪纸。幸运的是,聪明人已经找到了解决这些问题的方法,而不必使用丑陋的
开关,部分原因是
开关实际上并不更快,存在许多相同的问题。@speeder的“性能”问题在stackoverflow上总是有点问题(特别是对于C/C++标记),如果人们(a)不同意您的用例需要优化,(b)您正在考虑一个他们认为不如“标准做事方式”的优化,或者(c)认为答案很明显,您不应该问,那么他们似乎会对这些人投很低的票。这有点不幸,我同意这个问题不值得-4。这在很大程度上取决于编译器如何实现这一点,但至少在某些机器上,调用虚拟函数比调用开关更快。(对其他人来说,可能不是。)@JamesKanze我同意,但这仍然是一个微观优化。显然,选择一个解决方案而不是o
#include <stdio.h>

class Object
{
    public:
        // function pointer acting as virtual function call
        void (*funcPtr) (void *this_ptr);
};

class Button : public Object
{
    public:
        Button();
        static void virtualFunc(void *this_ptr);

        int counter;
};

Button::Button()
    :counter(0)
{
    // set object function pointer to our "virtual function"
    funcPtr = &Button::virtualFunc;
}

void Button::virtualFunc(void *this_ptr)
{
    Button *button_ptr = reinterpret_cast<Button*>(this_ptr);
    button_ptr->counter++;
}

int main()
{
    Object *button = new Button();

    // virtual call using a function pointer
    button->funcPtr(button);

    printf("button counter = %d\n", static_cast<Button*>(button)->counter);

    return 0;
}