没有虚函数的多态 [英] Polymorphism Without Virtual Functions

查看:202
本文介绍了没有虚函数的多态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试优化代码的运行时间,并被告知删除不必要的虚函数是解决之道.考虑到这一点,我仍然想使用继承来避免不必要的代码膨胀.我以为,如果我只是简单地重新定义了我想要的功能并初始化了不同的变量值,那么只要我需要派生类特定的行为,就可以将其向下转换到派生类中.

I am trying to optimize the run time of my code and I was told that removing unnecessary virtual functions was the way to go. With that in mind I would still like to use inheritance to avoid unnecessary code bloat. I thought that if I simply redefined the functions I wanted and initialized different variable values I could get by with just downcasting to my derived class whenever I needed derived class specific behavior.

因此,我需要一个变量来标识要处理的类的类型,以便可以使用switch语句正确地向下转换.我正在使用以下代码来测试这种方法:

So I need a variable that identifies the type of class that I am dealing with so I can use a switch statement to downcast properly. I am using the following code to test this approach:

Classes.h

Classes.h

#pragma once

class A {
public:
    int type;
    static const int GetType() { return 0; }
    A() : type(0) {}
};

class B : public A {
public:
    int type;
    static const int GetType() { return 1; }
    B() : {type = 1}
};

Main.cpp

#include "Classes.h"
#include <iostream>
using std::cout;
using std::endl;
using std::getchar;

int main() {
    A *a = new B();
    cout << a->GetType() << endl;
    cout << a->type;
    getchar();
    return 0;
}

我得到预期的输出:0 1

I get the output expected: 0 1

问题1:是否有更好的类型存储方式,这样我就不必为创建的对象的每个实例浪费内存了(就像static关键字允许的那样)?

Question 1: Is there a better way to store type so that I do not need to waste memory for each instance of the object created (like the static keyword would allow)?

问题2:将switch语句放入函数中以根据类型值决定应执行的操作是否更有效,或者switch语句-> downcast然后使用派生的类特定函数会更有效.

Question 2: Would it be more effective to put the switch statement in the function to decide that it should do based on the type value, or switch statement -> downcast then use a derived class specific function.

问题3:是否有更好的方法来处理我完全忽略的不使用虚函数的方法?例如,我应该创建一个具有许多相同变量的全新类

Question 3: Is there a better way to handle this that I am entirely overlooking that does not use virtual functions? For Example, should I just create an entirely new class that has many of the same variables

推荐答案

问题1:是否有更好的类型存储方式,这样我就不必为创建的对象的每个实例浪费内存了(就像static关键字允许的那样)?

Question 1: Is there a better way to store type so that I do not need to waste memory for each instance of the object created (like the static keyword would allow)?

RTTI已经启用了typeid(),您无需以容易出错且不可靠的方式实现自己.

There's the typeid() already enabled with RTTI, there's no need you implement that yourself in an error prone and unreliable way.

问题2:将switch语句放入函数中以根据类型值决定应执行的操作是否更有效,或者switch语句-> downcast然后使用派生的类特定函数会更有效.

Question 2: Would it be more effective to put the switch statement in the function to decide that it should do based on the type value, or switch statement -> downcast then use a derived class specific function.

当然不!这是(非常好!)类继承层次结构设计的重要指示.

Certainly no! That's a heavy indicator of bad (sic!) class inheritance hierarchy design.

问题3:是否有更好的方法来处理我完全忽略的不使用虚函数的方法?例如,我应该创建一个具有许多相同变量的全新类

Question 3: Is there a better way to handle this that I am entirely overlooking that does not use virtual functions? For Example, should I just create an entirely new class that has many of the same variables

无需使用virtual函数即可实现多态的典型方法是 CRTP (又名静态多态性).
这是一种广泛使用的技术,可以避免 虚拟功能表的开销. em> 当您真的不需要它们时,只想适应您的特定需求(例如,对于小型目标,在这些目标中低内存开销至关重要).

The typical way to realize polymorphism without usage of virtual functions is the CRTP (aka Static Polymorphism).
That's a widely used technique to avoid the overhead of virtual function tables when you don't really need them, and just want to adapt your specific needs (e.g. with small targets, where low memory overhead is crucial).

给出您的示例 1 ,结果将如下所示:

Given your example1, that would be something like this:

template<class Derived>
class A {
protected:
    int InternalGetType() { return 0; }
public:
    int GetType() { static_cast<Derived*>(this)->InternalGetType(); }
};

class B : public A<B> {
    friend class A<B>;
protected:
    int InternalGetType() { return 1; }
};

所有绑定将在编译时完成,并且运行时开销为零.
另外,使用static_cast确保安全绑定,如果B实际上没有继承A<B>,则会引发编译器错误.

All binding will be done at compile time, and there's zero runtime overhead.
Also binding is safely guaranteed using the static_cast, that will throw compiler errors, if B doesn't actually inherits A<B>.

不要使用该图案作为金锤!它也有缺点:

Don't use that pattern as a golden hammer! It has it's drawbacks also:

  • 提供抽象接口比较困难,并且如果没有事先的 type trait 检查或 concepts ,您将使客户难以理解.模板实例化时出现编译器错误消息.
  • 这不适用于像 plugin 这样的体系结构模型,在该模型中,您确实要具有 late绑定,并在运行时加载模块.

  • It's harder to provide abstract interfaces, and without prior type trait checks or concepts, you'll confuse your clients with hard to read compiler error messages at template instantiantion.
  • That's not applicable for plugin like architecture models, where you really want to have late binding, and modules loaded at runtime.

如果您对可执行文件的代码大小和性能没有真正的限制,则不值得进行必要的额外工作.对于大多数系统,您只需忽略使用virtual函数定义完成的调度开销.

If you don't have really heavy restrictions regarding executable's code size and performance, it's not worth doing the extra work necessary. For most systems you can simply neglect the dispatch overhead done with virtual function defintions.

1) GetType()的语义不一定是最好的,但是...

1)The semantics of GetType() isn't necessarily the best one, but well ...

这篇关于没有虚函数的多态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆