image.png

    1. #include <iostream>
    2. #include <cstring>
    3. using namespace std;
    4. class Animal
    5. {
    6. public:
    7. static int number;
    8. Animal() { number += 1; }
    9. virtual ~Animal() { number -= 1; } // 这里一定要用virtual,不然无法执行派生的析构函数
    10. };
    11. class Dog : public Animal
    12. {
    13. public:
    14. static int number;
    15. Dog()
    16. {
    17. Animal();
    18. number += 1;
    19. }
    20. ~Dog()
    21. {
    22. number -= 1;
    23. }
    24. };
    25. class Cat : public Animal
    26. {
    27. public:
    28. static int number;
    29. Cat()
    30. {
    31. Animal();
    32. number += 1;
    33. }
    34. ~Cat()
    35. {
    36. number -= 1;
    37. }
    38. };
    39. void print()
    40. {
    41. cout << Animal::number << " animals in the zoo, " << Dog::number << " of them are dogs, " << Cat::number << " of them are cats" << endl;
    42. }
    43. int Animal::number = 0; // 静态成员要声明
    44. int Dog::number = 0;
    45. int Cat::number = 0;
    46. int main()
    47. {
    48. print();
    49. Dog d1, d2;
    50. Cat c1;
    51. print();
    52. Dog *d3 = new Dog(); // new的这种也不会调用复制构造函数,毕竟是新建一个对象
    53. // 不是根据另一个已有对象来创建这个对象
    54. Animal *c2 = new Cat; // 主要是这一句比较难搞
    55. Cat *c3 = new Cat;
    56. print();
    57. delete c3;
    58. delete c2;
    59. delete d3;
    60. print();
    61. }
    • 为什么父类的析构函数不定义成虚函数,删除c2的时候就不会调用~Cat()了?而为什么即使把父类的析构函数定义成虚函数,调用子类的析构函数后仍然会调用父类的虚函数?

    【多态】virtual关键字 - 图2
    析构函数执行时先调用派生类的析构函数,其次才调用基类的析构函数。如果析构函数不是虚函数,而程序执行时又要通过基类的指针去销毁派生类的动态对象,那么用delete销毁对象时,只调用了基类的析构函数,未调用派生类的析构函数。这样会造成销毁对象不完全。

    • 静态成员变量要提前初始化