非虚拟派生:我真正从编译器得到什么?
我想知道使用非虚拟派生时编译器会产生什么:
template< unsigned int D >
class Point
{
int[D];
// No virtual function
// ...
};
class Point2 : public Point<2> {};
class Point3 : public Point<3> {};
这里的派生仅意味着编译时检查吗?或者还有其他开销吗?
我注意到我的编译器在使用 Point2 或直接使用 Point<2> 时会生成相同大小的对象。我推断推导不会产生虚函数表,因此,不会进行任何虚拟调用。
我错过了什么吗?
上下文
我想为给定的类模板提供几个预定义的专业化。我从 typedef 开始:
template< unsigned int D >
class Point
{
int[D];
};
typedef Point<2> Point2;
typedef Point<3> Point3;
唉,这会阻止客户端使用“简单”的前向声明:
// No #include <Point.h>
class Point2; // 'Point2': redefinition; different basic types
class Point3; // 'Point3': redefinition; different basic types
然后必须编写这段相当不直观的代码:
// No #include <Point.h>
template< unsigned int > class Point;
typedef Point<2> Point2;
typedef Point<3> Point3;
这就是我放弃 typedef 并使用非虚拟派生的原因。尽管如此,我还是想知道其中的含义是什么。
(另一种策略是在专用头文件中编写一次前向声明,就像 #include
一样。)
I am wondering what is produced by the compiler when using non-virtual derivation:
template< unsigned int D >
class Point
{
int[D];
// No virtual function
// ...
};
class Point2 : public Point<2> {};
class Point3 : public Point<3> {};
Does the derivation here only imply compile-time checks? Or is there some other overhead?
I noticed my compiler produces equally sized objects when using Point2
or directly Point<2>
. I deduce the derivation did not incur a vtable, and, as a consequence, no virtual call will ever be made.
Am I missing something?
Context
I want to provide a couple of predefined specializations of a given class template. I started with typedefs:
template< unsigned int D >
class Point
{
int[D];
};
typedef Point<2> Point2;
typedef Point<3> Point3;
Alas, this prevents clients to use "simple" forward declarations:
// No #include <Point.h>
class Point2; // 'Point2': redefinition; different basic types
class Point3; // 'Point3': redefinition; different basic types
It is then mandatory to write this rather unintuitive piece of code:
// No #include <Point.h>
template< unsigned int > class Point;
typedef Point<2> Point2;
typedef Point<3> Point3;
This is why I discarded typedefs and used non-virtual derivation. Still, I am wondering what are all the implications.
(Another strategy would be to write the forward declaration once in a dedicated header file, à la #include <iosfwd>
.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,看起来到目前为止没有人给你一个实际的答案:
不,非虚拟推导没有任何开销。
编译器不必创建 vtable,也没有虚拟函数调用,一切都很好。
它通常通过将基类的实例放置在派生类的开头来实现,这样指向派生类的指针也可以被视为指向基类的指针。然后一切就会正常工作。
当然,构造函数调用必须被转发,但它们通常会被内联,从而也消除了这种开销。
但是,如果您使用多个基类,则可能会引入一点点开销(取决于编译器如何实现它)。可能不多(
this
指针必须不时调整),但理论上,它是存在的。Ok, looks like no one have so far given you an actual answer to your question:
No, there is no overhead to non-virtual derivation.
The compiler doesn't have to create a vtable, there are no virtual function calls, and all is well.
It is typically implemented simply by placing an instance of the base class at the beginning of the derived class, so that a pointer to the derived class can be treated as a pointer to the base class as well. And then everything just works.
Of course, constructor calls have to be forwarded, but they will usually get inlined, eliminating that overhead as well.
However, if you use multiple base classes, it may introduce a tiny bit of overhead (depending on how the compiler implements it). Probably not much (the
this
pointer has to be adjusted from time to time), but theoretically, it is there.我真的不明白这里使用 typedef 有什么问题。这就是 typedef 的目的。我相信在命名空间中工作时存在一些限制,但看起来您并没有在这里这样做。看到这样的内容很常见:
General.h
然后您可以将其包含在源代码中,尽管您必须记住包含
MyObj1
的定义和MyObj2
编译器需要知道大小(即声明中的引用和指针除外)。I don't really see what the problem is with using typedefs here. This is the sort of thing that typedef was intended for. I believe that there are a few restrictions when working in namespaces, but it doesn't look like you're doing that here. It's quite common to see something like this:
General.h
You can then include that in your source code, though you'll have to remember to include the definition of
MyObj1
andMyObj2
where the compiler will need to know the size (i.e other than references and pointers in declarations.)由于以下原因,我总是使用前向声明(typedef 声明);
I always go with the forward declaration (the typedef one), because of the following reasons;
继承的问题是你必须重新定义构造函数。
标准解决方案(我不明白您为什么不想要它)是一个专用标头:
您的客户只需包含
"PointFwd.h"
即可转发声明他们想要的内容。The problem with inheritance is that you have to redefine the constructors.
The standard solution (I don't see why you don't want it) is a dedicated header:
Your clients only have to include
"PointFwd.h"
to forward declare what they want.