C++ 非虚拟派生:我从编译器中真正得到了什么?
我想知道使用非虚拟派生时编译器会产生什么:C++ 非虚拟派生:我从编译器中真正得到了什么?,c++,templates,derived-class,non-virtual-interface,C++,Templates,Derived Class,Non Virtual Interface,我想知道使用非虚拟派生时编译器会产生什么: template< unsigned int D > class Point { int[D]; // No virtual function // ... }; class Point2 : public Point<2> {}; class Point3 : public Point<3> {}; 唉,这会阻止客户端使用“简单”的转发声明: // No #include <Poi
template< unsigned int D >
class Point
{
int[D];
// No virtual function
// ...
};
class Point2 : public Point<2> {};
class Point3 : public Point<3> {};
唉,这会阻止客户端使用“简单”的转发声明:
// No #include <Point.h>
class Point2; // 'Point2': redefinition; different basic types
class Point3; // 'Point3': redefinition; different basic types
//否#包括
类点2;//'第2点:重新定义;不同的基本类型
类第3点;//'第三点:重新定义;不同的基本类型
然后,必须编写这段相当不直观的代码:
// No #include <Point.h>
template< unsigned int > class Point;
typedef Point<2> Point2;
typedef Point<3> Point3;
//否#包括
模板类点;
类型定义点2;
类型定义点3;
这就是我放弃typedef并使用非虚拟派生的原因。不过,我想知道这一切意味着什么
(另一种策略是在专用头文件中编写一次转发声明,即la
#include
)我真的不明白这里使用typedef有什么问题。这就是typedef的初衷。我相信在名称空间中工作时会有一些限制,但这里看起来并不是这样。这样的情况很常见:
常规.h
#include <map>
#include <string>
class MyObj1;
class MyObj2;
typedef map< string, MyObj1 > MyObj1Map;
typedef map< string, MyObj2 > MyObj2Map;
#包括
#包括
MyObj1类;
MyObj2类;
typedef mapMyObj1Map;
typedef mapMyObj2Map;
然后,您可以将其包含在源代码中,尽管您必须记住包含
MyObj1
和MyObj2
的定义,其中编译器需要知道大小(即声明中的引用和指针除外)。我不太明白这里使用typedef有什么问题。这就是typedef的初衷。我相信在名称空间中工作时会有一些限制,但这里看起来并不是这样。这样的情况很常见:
常规.h
#include <map>
#include <string>
class MyObj1;
class MyObj2;
typedef map< string, MyObj1 > MyObj1Map;
typedef map< string, MyObj2 > MyObj2Map;
#包括
#包括
MyObj1类;
MyObj2类;
typedef mapMyObj1Map;
typedef mapMyObj2Map;
然后,您可以将其包含在源代码中,尽管您必须记住包含
MyObj1
和MyObj2
的定义,其中编译器需要知道大小(即声明中的引用和指针除外)。我始终使用前向声明(typedef声明),由于以下原因,
由于以下原因,我总是使用远期申报单(typedef-one)
继承的问题是必须重新定义构造函数 标准解决方案(我不明白你为什么不想要它)是一个专用的标题:
// File PointFwd.h
#ifndef POINT_FWD_H
#define POINT_FWD_H 1
template <unsigned> class Point;
typedef Point<2> Point2;
typedef Point<3> Point3;
#endif
//文件PointFwd.h
#ifndef点_FWD_H
#定义点_FWD_H 1
模板类点;
类型定义点2;
类型定义点3;
#恩迪夫
您的客户端只需包含
“PointFwd.h”
即可向前声明所需内容。继承的问题是您必须重新定义构造函数
标准解决方案(我不明白你为什么不想要它)是一个专用的标题:
// File PointFwd.h
#ifndef POINT_FWD_H
#define POINT_FWD_H 1
template <unsigned> class Point;
typedef Point<2> Point2;
typedef Point<3> Point3;
#endif
//文件PointFwd.h
#ifndef点_FWD_H
#定义点_FWD_H 1
模板类点;
类型定义点2;
类型定义点3;
#恩迪夫
您的客户只需包含
“PointFwd.h”
即可向前声明他们想要的内容。好的,似乎到目前为止还没有人给您问题的实际答案:
不,非虚拟派生没有开销。
编译器不必创建vtable,没有虚拟函数调用,一切正常。
它通常只需将基类的实例放在派生类的开头即可实现,因此指向派生类的指针也可以视为指向基类的指针。然后一切都正常了
当然,构造函数调用必须被转发,但它们通常是内联的,这也消除了开销
但是,如果使用多个基类,则可能会引入少量开销(取决于编译器如何实现它)。可能不太多(必须不时调整
这个指针),但从理论上讲,它是存在的。好的,似乎到目前为止还没有人给您的问题提供实际答案:
不,非虚拟派生没有开销。
编译器不必创建vtable,没有虚拟函数调用,一切正常。
它通常只需将基类的实例放在派生类的开头即可实现,因此指向派生类的指针也可以视为指向基类的指针。然后一切都正常了
当然,构造函数调用必须被转发,但它们通常是内联的,这也消除了开销
但是,如果使用多个基类,则可能会引入少量开销(取决于编译器如何实现它)。可能不会太多(必须不时调整这个指针),但从理论上讲,它确实存在。对不起,typedefs有什么问题?我无法向前声明类模板的typedef。例如,我不能转发declare类ostream
,我必须#include
——从那篇文章中可以看出,您必须使用
的原因是正确的转发声明必须在std名称空间中完成,这对您来说是不合法的。我不明白为什么不能转发declare Point并将这些typedef放在专用的头文件中。@UncleBens:我引用GOTW的这篇文章的目的是举例说明专用转发声明头文件的使用。我可以使用这种技术,但我正在寻找另一种解决方案。对不起,typedefs有什么问题吗?我无法向前声明类模板的typedef。例如,我不能向前声明类ostream
和