如何在 C++ 中用静态多态性代替动态多态性?

Posted

技术标签:

【中文标题】如何在 C++ 中用静态多态性代替动态多态性?【英文标题】:How to in C++ substitute the dynamic polymorphism by the static one? 【发布时间】:2021-03-03 08:22:58 【问题描述】:

假设我有以下代码利用 C++ 中的动态多态性

GraphicalObject.h

class GraphicalObject

public:
    virtual void draw() = 0;
;

矩形.h

#include "GraphicalObject.h"

class Rectangle : public GraphicalObject

    void draw();
;

矩形.cpp

#include "Rectangle.h"
#include <iostream>

void Rectangle::draw() 
    std::cout << "Drawing rectangle!" << std::endl;

圆.h

#include "GraphicalObject.h"

class Circle : public GraphicalObject

    void draw();
;

Circle.cpp

#include "Circle.h"
#include <iostream>

void Circle::draw() 
    std::cout << "Drawing circle!" << std::endl;

主要

int main(int argc, char** argv) 

    Rectangle rectangle;
    Circle circle;

    GraphicalObject* picture[2];
    
    picture[0] = &rectangle;
    picture[1] = &circle;
    
    for(GraphicalObject* o : picture) 
        o->draw();
    
    
    return 0;

我的问题是是否有可能如何拥有picture 数组 没有动态多态性,而不是只使用静态多态性和 避免使用虚方法?我想避免使用虚拟方法的原因是我想避免与访问 vtable 相关的开销。

【问题讨论】:

如果你想像这样将它们存储在同一个数组中,则不是。 std::tuple&lt;Rectangle, Circle&gt; pictures; std::apply([](const auto&amp; shape) (shape.draw(), ...); , pictures)? 为什么要替换它?你想改进什么?好像你有一个经典的动态多态示例。 @AyxanHaqverdili 感谢您的回复。我的目的是避免与 v​​table 访问相关的开销。 【参考方案1】:

这里的问题是GraphicalObject* picture[2];指向的对象得到了静态类型GraphicalObject,而静态多态使用静态类型。

但这并不意味着静态多态是不可能的,类似的情况。你需要一个包装类,它知道存储对象的实际类型,并在调用方法之前将指针转换为它。

【讨论】:

派感谢您的回复。我可以请您概述一下您的想法吗? @Steve 真的取决于你真正想要达到的目标。在一般情况下,虚拟调用的替换恰好是其他形式的虚拟调用的实现,因为 vtable 指针只是指向成员指针数组的指针。虚拟调用的开销只是一个指针解引用。如果您只需要一个通用存储,它将包含多种类型的实例,但每个使用者将只使用一种类型,在这种情况下,静态多态允许通过内联它来排除 function 调用的开销,如果它可能的。你可能会使用std::variant

以上是关于如何在 C++ 中用静态多态性代替动态多态性?的主要内容,如果未能解决你的问题,请参考以下文章

C++静态多态与动态多态的实现原理剖析

C++多态底层剖析

C++多态底层剖析

C++多态 --- 多态实现原理简析

C++多态底层剖析

C++的动态多态与静态多态