C++虚函数

4

我在想,什么方法最快?如果我有一个像这样的基类:

Class Base
{
virtual void Draw()
{
//something...
}
};

那么我会有一个像这样的基本数组:

Base Array[255];

这里可能包含Base及其派生类。例如,存储各种绘图命令的一种方式。(我知道这似乎与Java相似,但这只是一个例子。只有一个函数的类并没有太多意义。)

或者,如果我确切地知道要创建哪些派生类,可以像这样完成:

class Base
{
int ID;
};

然后像之前一样创建一个Base数组:

Base Array[255];

接着在派生类中创建绘制函数:

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();
}

如果你知道导数,哪种方法更快呢?自己制作一个有组织的系统,还是使用虚拟函数?

还有其他需要考虑的因素吗?(比如代码清晰度,但我更喜欢在代码中展示我的类类型,所以我不介意强制转换。)


8
你现在不就是在自己实现虚函数表吗?那你希望节省什么呢? - µBio
7个回答

4

一定要使用虚函数,这正是它们的用途。自己重新实现容易出错,而且肯定不会更快。

此外,在您声明Array时需要使用指针:

Base *Array[255];

否则,在 C++ 中(与 Java 不同),数组只能包含 Base 的实例,而不能包含派生类的对象。使用指针更像是 Java 的引用,并允许将派生类的实例放入数组中。

2
еҫҲеҸҜиғҪжҳҜдёҖз»„shared_ptrжҲ–е…¶д»–жҷәиғҪжҢҮй’ҲпјҢеӣ дёәе®ғ们еҸҜиғҪйңҖиҰҒеҠЁжҖҒеҲҶй…ҚгҖӮ - GManNickG

2
使用虚函数,因为它们在逻辑上的作用几乎相同,但使用虚函数表查找,可能会更慢/更快(具体取决于实现方式)。然而,除非这是您代码的关键部分(这在99 / 100个情况下都不是),否则不要为此烦恼。
使用虚函数可以使您的代码更加简洁,而且您不必为自己的实现问题而烦恼,因为这些问题已经作为C ++的一部分存在。

1

我猜你是出于好奇而问,而不是因为你真的会尝试使用 switch 来实现它。

你必须将数组声明为 Base*,而不是 Base

虚函数调用是一个数组查找和函数调用。switch 通常被实现为简单的常数时间跳转。所以,它们都是 O(1),但我认为虚函数调用会更快,因为 C++ 编译器会优化使其更快,而 switch 并不能保证是 O(1)。


1
不要声明一个基础类型的值数组:会发生对象切割,而且你将失去虚拟调用。
虚拟调用“较慢”,但更易读。实际上,在取消虚拟调用方面几乎没有任何优势。如果你试图优化你的代码,我敢打赌有更好的地方可以看看。

0

我建议使用虚函数的方式来实现你的逻辑,原因如下:

(1) 我不知道你使用了多少个情况(case Implementation),但如果明天你的派生类扩展到50个甚至更多,你最终只会编写你的情况,无论你试图通过为派生类提供ID手动执行什么操作,这都是编译器的工作,它本身会插入初始化vptr和VTABLE代码的工作。最好的策略是“不要实现编译器可以自己实现的内容”。因此,在将来,无论你从基类派生出多少个类,通过虚函数的方式进行处理,你的代码将更好、更快、更易读。

(2) 在使用虚函数时,你必须始终在基类中将一个函数声明为虚函数,并通过向上转型(通过将派生类对象指针/引用分配给基类对象)访问派生类函数(具有相同名称)。在你的实现中,你没有提供任何基类指针或引用,它必须是Base * Arr[100]或Base & Arr[100]。

你在第二个问题中所做的是对象切片,即从对象中切掉了Base部分。

敬礼, Softy


0

使用虚函数。没得商量。


0
我强烈主张为了代码的整洁性和可维护性,您应该坚持使用虚函数。没有真正的理由避免使用它们。在这一点上它们相当有效(像Java这样的语言默认使用它们来处理所有非静态方法)。如果您实际上有必须要极其高效的代码,并且您正在尝试挤出每一个指令,那么您需要编写一个带有虚函数和一个不带虚函数的版本并进行分析。除此之外,不用担心。您正在尝试使用语言本身的方式来完成任务,而不是使用语言内置的方式,这很少是一个好主意。它甚至可能会更慢 - 只有分析才能说明。只需使用虚函数,不用担心。
另外,Base Array[255];不起作用,因为所有对象都将被削减为基础对象而不是派生类型。您需要使用指针:Base* Array[255];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接