• C++ 类和虚函数


    构造函数和析构函数可以是虚函数吗

    虚函数的调用通过虚表指针来指定,虚表指针包含在对象的内存空间中,它在构造函数调用后完成初始化;

    析构函数可以且常常是虚函数

    这个原理上就很好理解啦,因为此时 vtable 已经初始化了,完全可以把析构函数放在虚函数表里面来调用。

    C++类有继承时,析构函数必须为虚函数。如果不是虚函数,则使用时可能存在内存泄漏的问题。

    虚表存放在哪里

    C++ 虚函数表及多态内部原理详解(一)

    虚表是全局唯一的,放在全局数据区;

    虚函数和纯虚函数区别

    知乎-C++ 虚函数、纯虚函数

    对象的内存大小计算

    C++类所占内存大小计算_大副的博客-CSDN博客

    空类,大小占用为1;

    有虚函数,虚表指针占用为4;

    非static数据成员的占用;

    需要考虑内存对齐的问题;

    类的基本成员函数

    默认构造函数;

    析构函数;

    赋值运算符重载;

    拷贝构造函数;

    基类和派生类,基类指针指向派生类对象

    基类指针可以指向派生类对象,其中句柄类型也就是指针类型决定哪个类的函数被调用,如果是基类指针指向派生类,那么调用的函数还是基类的;

    但是,如果有了virtual以后,调用哪个版本的virtual函数则由句柄指向的对象来决定;也就是虽然指向的还是句柄,但是句柄仍然会指向派生类对象的虚表

    如下所示,使用基类D指向派生类E,在创建时调用E的构造函数,然后递归调用基类构造函数;在销毁时,调用D的析构函数,然后递归调用基类的析构函数;

    1. #include <iostream>
    2. using namespace std;
    3. // 基类和派生类的析构函数
    4. class C{
    5. public:
    6. C(){
    7. cout << "C constructor\n";
    8. }
    9. ~C(){
    10. cout << "C deconstructor\n";
    11. }
    12. };
    13. class D: public C{
    14. public:
    15. D(){
    16. cout << "D constructor\n";
    17. }
    18. ~D(){
    19. cout << "D deconstructor\n";
    20. }
    21. };
    22. class E:public D{
    23. public:
    24. E(){
    25. cout << "E constructor\n";
    26. }
    27. ~E(){
    28. cout << "E deconstructor\n";
    29. }
    30. };
    31. int main(){
    32. D* test = new E();
    33. delete test;
    34. return 0;
    35. }
    36. C constructor
    37. D constructor
    38. E constructor
    39. D deconstructor
    40. C deconstructor

    如果析构函数是虚函数,则结果如下: 

    1. #include <iostream>
    2. using namespace std;
    3. // 基类和派生类的析构函数
    4. class C{
    5. public:
    6. C(){
    7. cout << "C constructor\n";
    8. }
    9. virtual ~C(){
    10. cout << "C deconstructor\n";
    11. }
    12. };
    13. class D: public C{
    14. public:
    15. D(){
    16. cout << "D constructor\n";
    17. }
    18. ~D(){
    19. cout << "D deconstructor\n";
    20. }
    21. };
    22. class E:public D{
    23. public:
    24. E(){
    25. cout << "E constructor\n";
    26. }
    27. ~E(){
    28. cout << "E deconstructor\n";
    29. }
    30. };
    31. int main(){
    32. D* test = new E();
    33. delete test;
    34. return 0;
    35. }
    36. C constructor
    37. D constructor
    38. E constructor
    39. E deconstructor
    40. D deconstructor
    41. C deconstructor

  • 相关阅读:
    Mac桌面上的文件消失,Finder中可以访问到
    日语等级J.TEST的自测卷
    电脑下载视频号视频:微信视频号如何下载到电脑桌面上?
    网络安全原理与实践学习笔记——设计DMZ
    css 流式布局 九宫格布局
    【 网络带宽 】MBps & Mbps
    P1208 [USACO1.3] 混合牛奶 Mixing Milk
    Vue3加载element依赖步骤以及错误
    warning: The iOS deployment target ‘IPHONEOS_DEPLOYMENT_TARGET‘ is set to 9.0
    科技云报道:金融级高可用!天翼云TeleDB数据库如何实现容灾双活?
  • 原文地址:https://blog.csdn.net/qq_36383623/article/details/109261729