练习代码,该说的都在代码和注释里:
1 #include <string> 2 3 class BaseClass 4 { 5 private: 6 int pri; 7 protected: 8 int pro; 9 public: 10 int pub; 11 12 BaseClass() 13 { 14 printf("调用父类的构造函数! "); 15 to_string(); 16 } 17 18 // 将析构函数设置为虚函数,以便在应用多态特征的时候,能够调用子类的析构函数释放子类动态申请的空间 19 virtual ~BaseClass() 20 { 21 printf("调用父类的析构函数! "); 22 } 23 virtual void to_string() 24 { 25 printf("调用父类的to_string:我是父类! "); 26 } 27 void do_something() 28 { 29 printf("我什么也没干! "); 30 } 31 }; 32 33 class DerivedClassPub : public BaseClass 34 { 35 private: 36 char* name; 37 public: 38 DerivedClassPub() 39 { 40 printf("调用子类的构造函数! "); 41 pub = 1; // 还是public 42 pro = 1; // 还是protected 43 // pri = 1; 非法,不可访问 44 const char* str = "小强"; 45 name = new char[strlen(str)+1]; 46 strcpy(name, str); 47 to_string(); 48 } 49 ~DerivedClassPub() 50 { 51 printf("调用子类的析构函数! "); 52 53 // 如果父类的析构函数不是虚函数,在应用多态特性时:如使用父类的指针或者引用指向子类时,子类的析构函数不会被调用,动态申请的空间无法被释放 54 delete name; 55 name = NULL; 56 } 57 void to_string() 58 { 59 printf("调用子类的to_string:我是子类!我的名字是:%s ", name); 60 } 61 void do_something() 62 { 63 printf("我在跑步! "); 64 } 65 }; 66 67 class DerivedClassPro : protected BaseClass 68 { 69 public: 70 DerivedClassPro() 71 { 72 pub = 1; // 变成protected 73 pro = 1; // 还是protected 74 // pri = 1; 非法,不可访问 75 } 76 ~DerivedClassPro(){} 77 }; 78 79 class DerivedClassPri : private BaseClass 80 { 81 public: 82 DerivedClassPri() 83 { 84 pub = 1; // 变成private 85 pro = 1; // 变成private 86 // pri = 1; 非法,不可访问 87 } 88 ~DerivedClassPri(){} 89 }; 90 91 class AnotherBaseClass 92 { 93 public: 94 AnotherBaseClass() 95 { 96 printf("调用父类的构造函数! "); 97 } 98 ~AnotherBaseClass() 99 { 100 printf("调用父类的析构函数! "); 101 } 102 }; 103 class AnotherDerivedClass : public AnotherBaseClass 104 { 105 public: 106 AnotherDerivedClass() 107 { 108 printf("调用子类的构造函数! "); 109 } 110 ~AnotherDerivedClass() 111 { 112 printf("调用子类的析构函数! "); 113 } 114 }; 115 116 int main() 117 { 118 // 构造的时候,先调用父类的构造函数,若其中调用了任何虚函数和非虚函数,均是父类的函数,因为此时还没构造出子类的那部分,换句话说,现在才构造了一半 119 BaseClass* base = new DerivedClassPub(); 120 121 // 因为析构函数是虚函数,所以调用子类的析构函数,之后再调用父类的析构函数,为什么? 122 printf(">> 当析构函数是虚函数时: "); 123 delete base; 124 printf("<< 结束! "); 125 base = NULL; 126 127 AnotherBaseClass* another_base = new AnotherDerivedClass(); 128 printf(">> 当析构函数不是虚函数时: "); 129 delete another_base; 130 printf("<< 结束! "); 131 another_base = NULL; 132 133 DerivedClassPub* d = new DerivedClassPub(); 134 printf(">> 当析构函数是虚函数时: "); 135 delete d; 136 printf("<< 结束! "); 137 d = NULL; 138 139 AnotherDerivedClass* ad = new AnotherDerivedClass(); 140 printf(">> 当析构函数不是虚函数时: "); 141 delete ad; 142 printf("<< 结束! "); 143 ad = NULL; 144 145 return 0; 146 }
输出结果:
调用父类的构造函数! 调用父类的to_string:我是父类! 调用子类的构造函数! 调用子类的to_string:我是子类!我的名字是:小强 >> 当析构函数是虚函数时: 调用子类的析构函数! 调用父类的析构函数! << 结束! 调用父类的构造函数! 调用子类的构造函数! >> 当析构函数不是虚函数时: 调用父类的析构函数! << 结束! 调用父类的构造函数! 调用父类的to_string:我是父类! 调用子类的构造函数! 调用子类的to_string:我是子类!我的名字是:小强 >> 当析构函数是虚函数时: 调用子类的析构函数! 调用父类的析构函数! << 结束! 调用父类的构造函数! 调用子类的构造函数! >> 当析构函数不是虚函数时: 调用子类的析构函数! 调用父类的析构函数! << 结束! 请按任意键继续. . .