C++ :使方法成为虚拟的含义

发布于 2024-08-13 08:27:22 字数 359 浏览 10 评论 0原文

应该是一个新手问题...

我在现有类 A 中有现有代码,我想扩展它以覆盖现有方法 A::f()。

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

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

我的问题是除了允许动态调用方法(使用 B 的实现而不是 A 的实现)之外,使方法虚拟化还有其他含义吗?我是否违反了某种良好的编程实践?这会影响尝试使用 A::f() 的任何其他代码吗?

请告诉我。

谢谢, jbu

编辑:我的问题更多的是使别人的方法虚拟化有什么问题吗?即使您没有更改其他人的实现,您仍然必须进入某人的现有代码并对声明进行更改。

Should be a newbie question...

I have existing code in an existing class, A, that I want to extend in order to override an existing method, A::f().

So now I want to create class B to override f(), since I don't want to just change A::f() because other code depends on it.

To do this, I need to change A::f() to a virtual method, I believe.

My question is besides allowing a method to be dynamically invoked (to use B's implementation and not A's) are there any other implications to making a method virtual? Am I breaking some kind of good programming practice? Will this affect any other code trying to use A::f()?

Please let me know.

Thanks,
jbu

edit: my question was more along the lines of is there anything wrong with making someone else's method virtual? even though you're not changing someone else's implementation, you're still having to go into someone's existing code and make changes to the declaration.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

初吻给了烟 2024-08-20 08:27:22

如果在基类内部使该函数成为虚拟函数,则从该函数派生的任何函数也都将成为虚拟函数。

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

如果创建 B 的实例并将其存储在 A* 类型的指针中。然后你调用A*::->f,那么它就会调用BB::f

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

还有一个非常小的副作用,可能有一个类 C 也派生自 A,并且它可能实现 C::f,并且期望如果 A*::- >f 被调用,然后它期望 A::f 被调用。但这种情况并不常见。

但更有可能的是,如果 C 存在,那么它根本不会实现 C::f,在这种情况下一切都很好。


但要小心,如果您使用的是已经编译的库并且正在修改它的头文件,则您期望的工作可能不会。您将需要重新编译头文件和源文件。

您可以考虑执行以下操作以避免副作用:

  1. 创建从 A 派生的类型 A2 并将其设为 f 虚拟
    • 使用A2类型的指针代替A
    • 从类型 A2 派生 B
    • 通过这种方式,任何使用 A 的东西都会以同样的方式保证工作

根据您的需要,您也可以使用 has-a 关系而不是 is-a

If you make the function virtual inside of the base class, anything that derives from it will also have it virtual.

Once virtual, if you create an instance of A, then it will still call A::f.

If you create an instance of B and store it in a pointer of type A*. And then you call A*::->f, then it will call B's B::f.

As for side effects, there probably won't be any side effects, other than a slight (unnoticeable) performance loss.

There is a very small side effect as well, there could be a class C that also derives from A, and it may implement C::f, and expect that if A*::->f was called, then it expects A::f to be called. But this is not very common.

But more than likely, if C exists, then it does not implement C::f at all, and in which case everything is fine.


Be careful though, if you are using an already compiled library and you are modifying it's header files, what you are expecting to work probably will not. You will need to recompile the header and source files.

You could consider doing the following to avoid side effects:

  1. Create a type A2 that derives from A and make it's f virtual
    • Use pointers of type A2 instead of A
    • Derive B from type A2.
    • In this way anything that used A will work in the same way guaranteed

Depending on what you need you may also be able to use a has-a relationship instead of a is-a.

淡淡绿茶香 2024-08-20 08:27:22

每次调用虚拟函数时,都会进行虚拟表查找,这会带来一些隐含的性能损失。如果它不是虚拟的,则函数调用是直接的,因为代码位置在编译时是已知的。而在运行时,必须从您所调用的对象的虚函数表中引用虚函数地址。

There is a small implied performance penalty of a vtable lookup every time a virtual function is called. If it were not virtual, function calls are direct, since the code location is known at compile time. Wheras at runtime, a virtual function address must be referenced from the vtable of the object you're calling upon.

紫瑟鸿黎 2024-08-20 08:27:22

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

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

由于 vtable,虚拟函数还存在内存开销(除了 spoulson 提到的内容)

To do this, I need to change A::f() to
a virtual method, I believe.

Nope, you do not need to change it to a virtual method in order to override it. However, if you are using polymorphism you need to, i.e. if you have a lot of different classes deriving from A but stored as pointers to A.

There's also a memory overhead for virtual functions because of the vtable (apart from what spoulson mentioned)

他是夢罘是命 2024-08-20 08:27:22

还有其他方法可以实现您的目标。 B 成为 A 有意义吗?例如,猫成为动物是有意义的,但猫成为狗则没有道理。如果 A 和 B 相关的话,也许它们都应该从基类派生。

是否只有常见的功能可以分解?在我看来,您永远不会多态地使用这些类,而只需要这些功能。我建议您去掉通用功能,然后创建两个单独的类。

至于成本,如果您直接使用 A 和 B,编译将绕过任何虚拟调度,直接进行函数调用,就好像它们从来都不是虚拟的一样。如果您将 B 传递到需要 `A1 (作为引用或指针)的位置,那么它将必须进行调度。

There are other ways of accomplishing your goal. Does it make sense for B to be an A? For example, it makes sense for a Cat to be an Animal, but not for a Cat to be a Dog. Perhaps both A and B should derive from a base class, if they are related.

Is there just common functionality you can factor out? It sounds to me like you'll never be using these classes polymorphically, and just want the functionality. I would suggest you take that common functionality out and then make your two separate classes.

As for cost, if you're using A ad B directly, the compile will by-pass any virtual dispatching and just go straight to the functions calls, as if they were never virtual. If you pass a B into a place expecting `A1 (as a reference or pointer), then it will have to dispatch.

呆头 2024-08-20 08:27:22

谈到虚拟方法时,有两个性能问题。

  • vtable 调度,真正不用担心
  • 虚拟函数永远不会内联,这可能比前一个更糟糕,函数内联在某些情况下确实可以加快速度,而虚拟函数永远不会发生这种情况。

There are 2 performance hits when speaking about virtual methods.

  • vtable dispatching, its nothing to really worry about
  • virtual functions are never inlined, this can be much worse than the previous one, function inlining is something that can really speed things in some situations, it can never happen with a virtual function.
霞映澄塘 2024-08-20 08:27:22

改变别人的代码是否合法完全取决于当地的风俗习惯。这不是我们能为您回答的问题。

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

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

How kosher it is to change somebody else's code depends entirely on the local mores and customs. It isn't something we can answer for you.

The next question is whether the class was designed to be inherited from. In many cases, classes are not, and changing them to be useful base classes, without changing other aspects, can be tricky. A non-base class is likely to have everything private except the public functions, so if you need to access more of the internals in B you'll have to make more modifications to A.

If you're going to use class B instead of class A, then you can just override the function without making it virtual. If you're going to create objects of class B and refer to them as pointers to A, then you do need to make f() virtual. You also should make the destructor virtual.

漫雪独思 2024-08-20 08:27:22

在适当的地方使用虚拟方法是一种很好的编程习惯。虚拟方法对于 C++ 类的合理程度有很多影响。

如果没有虚函数,您就无法在 C++ 中创建接口。接口是一个具有所有未定义虚函数的类。

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

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

C++ 有很多陷阱,这就是为什么人们需要非常清楚他们想要做什么以及做这件事的最佳方法是什么。与 Java 或 C# 等运行时动态 OO 编程语言相比,做某事的方法并不像看起来那么多。有些方法要么是完全错误的,要么随着代码的发展最终导致未定义的行为。

既然你问了一个非常好的问题:D,我建议你购买 Scott Myer 的书:Effective C++ 和 Bjarne Stroustrup 的书:C++ 编程语言。这些将教您 C++ 中 OO 的微妙之处,特别是何时使用什么功能。

It is good programming practise to use virtual methods where they are deserved. Virtual methods have many implications as to how sensible your C++ Class is.

Without virtual functions you cannot create interfaces in C++. A interface is a class with all undefined virtual functions.

However sometimes using virtual methods is not good. It doesn't always make sense to use a virtual methods to change the functionality of an object, since it implies sub-classing. Often you can just change the functionality using function objects or function pointers.

As mentioned a virtual function creates a table which a running program will reference to check what function to use.

C++ has many gotchas which is why one needs to be very aware of what they want to do and what the best way of doing it is. There aren't as many ways of doing something as it seems when compared to runtime dynamic OO programming languages such as Java or C#. Some ways will be either outright wrong, or will eventually lead to undefined behavior as your code evolves.

Since you have asked a very good question :D, I suggest you buy Scott Myer's Book: Effective C++, and Bjarne Stroustrup's book: The C++ Programming Language. These will teach you the subtleties of OO in C++ particularly when to use what feature.

篱下浅笙歌 2024-08-20 08:27:22

如果这是该类将拥有的第一个虚拟方法,那么它就不再是 POD。这可能会破坏事情,尽管这种可能性很小。

POD:http://en.wikipedia.org/wiki/Plain_old_data_structs

If thats the first virtual method the class is going to have, you're making it no longer a POD. This can break things, although the chances for that are slim.

POD: http://en.wikipedia.org/wiki/Plain_old_data_structures

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文