1. 首页
  2. 编程语言
  3. C++ 
  4. Learning ROS for Robotics Programming - Second Edition

Learning ROS for Robotics Programming - Second Edition

上传者: 2024-07-23 21:00:38上传 PDF文件 14.32MB 热度 5次

14.8虚函数和构造函数

当创建一个包含有虚函数的对象时,必须初始化它的VPTR以指向相应的VTABLE。这必须在有关虚函数的任何调用之前完成。正如我们可能猜到的,因为构造函数有使对象成为存在物的工作,所以它也有设置VPTR的工作。编译器在构造函数的开头部分秘密地插入能初始化VPTR的代码。事实上,即使我们没有对一个类创建构造函数,编译器也会为我们创建一个带有相应VPTR初始化代码的构造函数(如果有虚函数)。这有几个含意。首先这涉及效率。内联(inline)函数的理由是对小函数减少调用代价。如果C++不提供内联(inline)函数,预处理器就可能被用以创建这些“宏”。然而,预处理器没有通道或类的概念,因此不能被用以创建成员函数宏。有了由编译器插入隐藏代码的构造函数,预处理宏根本不能工作。当寻找效率漏洞时,我们必须明白,编译器正在插入隐藏代码到我们的构造函数中。这些隐藏代码不仅必须初始化VPTR,而且还必须检查this的值(万一operator new返回零)和调用基类构造函数。放在一起,这些代码能影响我们认为是一个小内联函数的调用。特别是,构造函数的规模会抵消减少函数调用节省的费用。如果做大量的内联构造函数调用,我们的代码长度就会增长,而在速度上没有任何好处。当然,我们也许并不会立即把这些小构造函数都变成非内联,因为它们更容易做为内联的来写。但是,当我们正在调整我们的代码时,记住,务必去掉这些构造函数的内联性。

14.8.1构造函数调用次序

构造函数和虚函数的第二个有趣的方面涉及构造函数的调用顺序和在构造函数中虚函数调用的方法。所有基类构造函数总是在继承类构造函数中被调用。这是有意义的,因为构造函数有一项专门的工作:确保对象被正确的建立。派生类只访问它自己的成员,而不访问基类的成员,只有基类构造函数能恰当地初始化它自己的成员。因此,确保所有的构造函数被调用是很关键的,否则整个对象不会适当地被构造。这就是为什么编译器强制构造函数对派生类的每个部分调用。如果不在构造函数初始化表达式表中显式地调用基类构造函数,它就调用缺省构造函数。如果没有缺省构造函数,编译器将报告出错。(在这个例子中,class x没有构造函数,所以编译器能自动创建一个缺省构造函数。)构造函数调用的顺序是重要的。当继承时,我们必须完全知道基类和能访问基类的任何public和protected成员。这也就是说,当我们在派生类中时,必须能肯定基类的所有成员都是有效的。在通常的成员函数中,构造已经发生,所以这个对象的所有部分的成员都已经建立。然而,在构造函数内,必须想办法保证所有我们的成员都已经建立。保证它的唯一方法是让基类构造函数首先被调用。这样,当我们在派生类构造函数中时,在基类中我们能访问的所有成员都已经被初始化了。在构造函数中,“必须知道所有成员对象是有效的”也是下面做法的理由:只要可能,我们应当在这个构造函数初始化表达式表中初始化所有的成员对象(放在合成的类中的对象)。只要我们遵从这个做法,我们就能保证所有基类成员和当前对象的成员对象已经被初始化。

想深入了解为什么构造函数不能声明为虚函数?可以访问这里。还有疑惑为什么C++中构造函数中调用虚函数是如此复杂?请查看这个链接获取更多信息。

更详细的C++虚函数与虚函数表的分析,建议参考这篇文章。对于C++多态性和虚函数的不同应用,建议您进一步阅读C++虚基类虚函数虚析构函数

了解更多关于构造函数的初始化方法,请点击这里。如果您对虚函数的执行过程有更深入的兴趣,可以参考虚函数被类的构造析构函数和成员函数调用虚函数的执行过程

用户评论