c++虚函数
只是想知道,什么最快?如果我有一个像这样的基类
Class Base
{
virtual void Draw()
{
//something...
}
};
,那么我将有一个像这样的 Base 数组:
Base Array[255];
它可以包含 Base 及其派生类。例如,这将是存储各种绘图命令的一种方式。 (我知道这看起来像java,但这只是为了举例。只有一个函数的类没有多大意义。)
现在,或者,如果我确切地知道我将制作什么衍生品,那么可以像这样
class Base
{
int ID;
};
完成像以前一样的 Base 数组: 基本数组[255];
然后在导数中创建 Draw 函数:
class Der1 : Base
{
void Draw()
{
}
};
class Der2 : Base
{
void Draw()
{
}
};
现在,这个解决方案当然不允许我只循环数组并为每个对象调用 Draw 。相反,它必须做这样的事情。
void CallDraw()
{
for (int i = 0; i < 255; i++)
{
switch(Array[i].ID)
{
case 1: //Der1
( (Der1) Array[i] ) . Draw();
case 2: //Der2
( (Der2) Array[i] ) . Draw();
}
是的,对于那些到目前为止已经阅读过的人来说,这是真正的问题。如果您知道导数,哪个会更快?自己制作一个有组织的系统,还是使用虚拟功能?
还有其他需要考虑的事情吗? (也许是代码整洁,但我更喜欢在代码中展示我的类类型,所以我不会被强制转换所困扰。
Just wondering, what would be fastest? If I had a base class like this
Class Base
{
virtual void Draw()
{
//something...
}
};
Then I would have an array of Base like this:
Base Array[255];
Which could contain both Base and it's derivatives. This would be one way of for example, storing various drawing commands. (I know this would seem java-like, but it's just for the example. Classes with just one function doesn't make much sense.)
Now alternatively, if I knew exactly what derivatives I would make it could be done like this
class Base
{
int ID;
};
then an array of Base like before:
Base Array[255];
And then create the Draw functions in the derivatives:
class Der1 : Base
{
void Draw()
{
}
};
class Der2 : Base
{
void Draw()
{
}
};
Now, this solution of course doesn't allow me to just loop through the array and call Draw for each object. Instead it would have to be done something like this.
void CallDraw()
{
for (int i = 0; i < 255; i++)
{
switch(Array[i].ID)
{
case 1: //Der1
( (Der1) Array[i] ) . Draw();
case 2: //Der2
( (Der2) Array[i] ) . Draw();
}
And yeah, to those who have read so far, the actual question. Which would be faster, if you knew the derivatives? Making an organized system yourself, or using virtual functions?
And are there other things to take into consideration? (code cleanness maybe, but I rather like to show off what my class type is in the code, so I'm not bothered by the casts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
一定要使用虚函数,这正是它们的用途。自己重新实现很容易出错,而且速度肯定不会更快。
另外,在
Array
声明中,您需要使用指针:否则,在 C++ 中(与 Java 不同),数组只能包含
Base
的实例> 并且没有派生类的对象。使用指针更像是 Java 的引用,允许您将派生类的实例放入数组中。Definitely use virtual functions, that's precisely what they are for. Reimplementing it yourself is error-prone and certainly isn't going to be faster.
Also, in your declaration of
Array
you need to use pointers:Otherwise, in C++ (unlike Java), the array could only contain instances of
Base
and no objects of derived classes. Using a pointer is more like Java's references and allows you to put instances of derived class into the array.使用虚拟函数,因为从逻辑角度来说,它们的行为方式几乎相同,但是使用虚拟函数表查找,这可能会更慢/更快(取决于实现)。 不过,除非这是代码的关键部分(这是 99 / 100 的情况),否则不要为此类事情而烦恼。
使用虚拟函数可以使您的代码更干净,并且您不必为与您自己的 C++ 中已经存在的某些内容的实现相关的问题而烦恼。
Use virtual functions, because in logical terms they act pretty the same way, but using the virtual function table lookup, which might be slower / faster (depending on the implementation). Still, unless this is the critical part of your code (and that's 99 / 100 cases), don't bother yourself with such kinds of things.
Usage of virtual functions makes your code cleaner and you won't have to bother yourself with problems related to your own implementations of something that already exists as a part of C++.
我认为您是出于好奇而问的,而不是因为您实际上会尝试使用开关来实现它。
您必须将数组设置为
Base*
,而不是Base
虚拟调用是数组查找和函数调用。开关通常被实现为简单的恒定时间跳跃。因此,它们都是 O(1),但我认为虚拟调用会更快,因为 C++ 编译器将进行优化以使其更快,并且不能保证切换是 O(1)。
I assume you're asking out of curiosity -- not because you would actually try to implement it with a switch.
You have to make your array
Base*
, notBase
A Virtual call is an array lookup and function call. A switch is often implemented as a simple constant-time jump. So, they are both O(1), but I think the virtual call would be faster since C++ compilers would be optimized to make that fast, and the switch isn't guaranteed to be O(1).
不要声明 Base 类型的值数组:将会发生对象切片,而且,您将丢失虚拟呼叫。
虚拟调用“更慢”,但更具可读性。事实上,像这样的去虚拟化调用几乎没有任何优势。如果您正在尝试优化代码,我敢打赌还有更好的地方值得关注。
Don’t declare an array of values of Base type: object slicing will occur and, moreover, you will lose the virtual calls.
The virtual call is “slower,” but more readable. Really, there hardly is any advantage in devirtualizing calls like that. If you’re trying to optimize your code, I bet there are better places to look at.
寻求虚拟功能。时期。
Go for virtual functions. Period.
我强烈认为,为了代码的简洁性和可维护性,您应该坚持使用虚拟函数。没有真正的理由要避免它们。它们在这一点上相当有效(像 Java 这样的语言默认将它们用于所有非静态方法)。如果您实际上拥有必须非常高效的代码,并且您试图尽可能地从中提取最后一条指令,那么您需要编写一个带有虚拟函数的版本和一个不带有虚拟函数的版本,并对其进行分析。除此之外,不用担心。您试图做语言本身所做的事情,而不实际使用该语言的内置方法,这很少是一个好主意。它甚至可能会更慢——只有分析才能告诉我们。使用虚函数就行了,不用管它。
此外,
Base Array[255];
不起作用,因为所有对象都将被剪切并且仅是基对象而不是派生类型。您需要使用指针:Base* Array[255];
。I would strongly argue that for cleanliness of code and maintainability that you stick to using virtual functions. There's no real reason to avoid them. They are fairly efficient at this point (languages like Java use them by default for all non-static methods). If you actually had code that had to be insanely efficient and you were trying to eke every single last instruction out of it that you could, then you'd need to write both a version with virtual functions and one without and profile it. Other than that, don't worry about it. You're trying to do what the language itself does without actually using the language's built-in way of doing it, and that's rarely a good idea. It might even be slower - only profiling would tell. Just use virtual functions and don't worry about it.
Also,
Base Array[255];
is not going to work because all of your objects will get sheared and be only Base objects rather than the derived types. You need to use pointers:Base* Array[255];
.由于以下原因,我建议使用虚函数方式来实现您的逻辑
(1)我不知道您正在使用多少个案例(案例实现),但如果明天您的派生类扩展到超过 50 个甚至更多你最终只会编写你的案例,无论你试图通过向派生类提供 Id 来手动执行什么操作,都是编译器的工作,编译器本身会插入初始化 vptr 的代码,并且 VTABLE. 最佳策略是“不要实现编译器可以自行实现的内容”。
因此,将来无论您从基础派生出多少类,通过虚函数的方式,您的代码都会更好、更快且更具可读性。
(2) 使用虚函数时,必须始终在基类中将函数设为虚函数,并通过访问派生类函数(具有相同的名称) >向上转型(通过将派生类对象指针/引用分配给基类对象)。您没有在实现中提供任何基类指针或引用,它必须是 Base * Arr[100] 或 Base & Arr[100]
您在第二步中所做的是对象切片,即从对象中切下 Base 部分。
RGDS,
软软的
I will suggest to go with the virtual function way to implement you logic due to following reasons
(1) I don't know how many cases (case Implementation) you are using but if tomorrow your derived classes extends to more than 50 or even more you will end up writing your cases only , what ever you are trying to do manually by providing the Ids to the derived classes is the job of the compiler which itself inserts the code of initializing the vptr and the VTABLE.best policy is "Not to implement what a compiler can implement by itself" .
So in future no matter how many classes you derive out of base your code will be better,faster and more readable by virtual function way of doing.
(2) While using the virtual function you have to always always make a function virtual in the base class and access the derived class function(with the same name) by upcasting( by assigning the derived class object pointer/reference to the base class object).You haven't provided any base class pointer or reference in your implementation, it has to be Base * Arr[100] or Base & Arr[100]
What you are doing in 2nd is object slicing, where you are slicing the Base part from the object.
rgds,
Softy