2009-11-30 65 views
2

应该是一个新手的问​​题的方法的含义......C++:使虚拟

我已经在现有的类,A现有的代码,我想,以覆盖现有的方法中,A ::延长F()。

所以现在我想创建类B来覆盖f(),因为我不想只改变A :: f(),因为其他代码依赖于它。

为此,我需要将A :: f()更改为虚拟方法,我相信。

我的问题是除了允许动态调用一个方法(使用B的实现而不是A)之外,还有其他任何让方法变为虚拟的含义吗?我打破了一些良好的编程习惯吗?这会影响其他试图使用A :: f()的代码吗?

请让我知道。

感谢, JBU

编辑:我的问题是沿的线条更是有什么问题让别人的方法,虚拟?即使你没有改变别人的实现,你仍然需要进入某人现有的代码并对声明进行修改。

+3

你不能仅仅加上'virtual'在头一个第三方组件和它的工作 - 你将需要重新编译该组件为好。 – 2009-11-30 18:45:12

+0

许多人给你有用的答案,你没有打扰他们,或接受答案。那不好。 – 2009-12-07 17:30:44

回答

6

如果您在基类内部虚拟函数,则从它派生的任何内容都将使其具有虚拟性。

一旦虚拟,如果您创建了A的实例,那么它仍然会调用A::f

如果您创建B的实例并将其存储在类型为A*的指针中。然后您拨打A*::->f,然后拨打BB::f

至于副作用,可能不会有任何副作用,除了轻微(不明显)的性能损失。

有一个非常小的副作用,以及,有可能是C类也从A派生,它可以实现C::f,并预计,如果A*::->f被调用,那么预计A::f被调用。但这不是很常见。

但很有可能,如果存在C,那么它根本不会执行C::f,并且在这种情况下一切正常。


不过要小心,如果你使用的是已编译的库和要修改它的头文件,你期待的工作可能不会。您将需要重新编译头文件和源文件。

你可以考虑做以下,以避免副作用:

  1. 创建一个类型A2A派生并使它的A2f虚拟
    • 使用指针,而不是A
    • A2类型导出B
    • 这样任何使用的将在相同的方式工作保证

取决于你需要什么,你也可以使用一个has-a关系,而不是一个is-a的。

+0

感谢您的回复。我想我的问题更多的是*有没有什么错误*使别人的方法是虚拟的? – jbu 2009-11-30 18:38:12

+0

更新了我的答案。 – 2009-11-30 18:47:02

4

每次调用虚拟函数时,vtable查找的隐含性能损失都很小。如果它不是虚拟的,函数调用是直接的,因为代码位置在编译时是已知的。 Wheras在运行时,虚拟函数地址必须从您要调用的对象的vtable中引用。

+3

曾经有人评论说,虚拟功能对性能的影响就像剪发对体重的影响。 – 2009-11-30 18:44:40

2

还有其他的方式来实现你的目标。 B是否是A?例如,猫是一只动物,但不是猫是狗。也许A和B都应该从基类派生,如果它们是相关的。

是否只有可以分解的常用功能?这听起来像你永远不会使用这些类多态,只是想要的功能。我建议你把这个通用的功能拿出来,然后再做两个单独的课程。

至于成本,如果您直接使用A ad B,编译将绕过任何虚拟调度,直接进入函数调用,就好像它们从不虚拟一样。如果您将B传递到期望`A1(作为引用或指针)的地方,那么它将不得不派遣。

4

为此,我需要将A :: f()更改为 一个虚拟方法,我相信。

不,您不需要将其更改为虚拟方法以覆盖它。但是,如果你正在使用多态性,你需要,即如果你有很多不同的类从A派生,但存储为指针指向A.

由于vtable还有虚拟功能的内存开销(除了什么spoulson提到)

1

这是一个很好的编程习惯,在他们应得的地方使用虚拟方法。虚拟方法对你的C++类有多明智有很多含义。

没有虚拟函数,你不能在C++中创建接口。接口是一个包含所有未定义的虚函数的类。

但是有时使用虚拟方法并不好。使用虚拟方法来改变对象的功能并不总是有意义的,因为它意味着子分类。通常你可以使用函数对象或函数指针来改变功能。

如前所述,虚拟函数会创建一个表,运行的程序将引用该表来检查要使用的函数。

C++有许多问题,这就是为什么人们需要非常了解他们想要做什么以及做什么的最佳方式。与运行时动态OO编程语言(如Java或C#)相比,似乎没有尽可能多的方式进行某些操作。有些方法可能完全错误,或者随着代码的发展最终导致未定义的行为。

由于您提出了一个非常好的问题:D,我建议您购买Scott Myer的Book:Effective C++和Bjarne Stroustrup的书:The C++ Programming Language。这些将教会你在C++中的OO的细微之处,特别是何时使用什么特性。

2

当谈论虚拟方法时,有2个性能点击。

  • 虚函数表的调度,它没有真正担心
  • 虚函数从不内联,这可能是比前一个更糟糕,内联函数的东西,可以真正加快在某些情况下的东西,它永远不可能发生虚拟功能。
2

它是如何改变别人的代码完全取决于当地的习俗和习俗。这不是我们可以为你解答的问题。

接下来的问题是该类是否被设计为继承。在许多情况下,类不是,并且改变它们成为有用的基类,而不改变其他方面,可能会很棘手。一个非基类可能拥有除公共函数外都是私有的,所以如果你需要访问B中的更多内部,你必须对A进行更多的修改。

如果你打算使用B类而不是A类,那么你可以重写该函数而不使其变为虚拟。如果您要创建类B的对象并将它们引用为A的指针,那么您确实需要使f()为虚拟。你也应该使析构函数为虚拟。