上代码,该说的都在代码及注释里:
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string> 4 5 using namespace std; 6 7 class BaseClass 8 { 9 protected: 10 // 普通变量 11 int data; 12 13 // 地址不可变,但内容可变的常量 14 // 必须在初始值设定项列表中初始化 15 char* const name; 16 private: 17 18 // 内容不可变常量 19 // 必须初始值设定项列表中初始化 20 const int id; 21 22 // 类的全部实例共享的变量 23 // 在任意函数中都可以赋值,但是,这样做不符合其static的意义 24 // 合理的使用方式是在类外初始化,否则没有合适的赋初值的方式 25 static int count; 26 27 // 类的全部实例共享的常量 28 // 不能在初始值设定项列表中初始化,初始值设定项列表只能处理非static类型的成员 29 // 不能在任何函数中赋值 30 // 所以只能类外初始化 31 static const int max; 32 public: 33 // 关于“是不是所有成员函数都可以声明称虚函数的问题” 34 // 下面的语句不合法! 35 // error C2633: “BaseClass”:“inline”是构造函数的唯一合法存储类 36 // virtual BaseClass(){} 37 38 // 关于“const类型的成员变量初始化的问题” 39 // 下面的语句不合法! 40 // error C2758: “BaseClass::idx和BaseClass::name””: 必须在构造函数基/成员初始值设定项列表中初始化 41 // BaseClass(){} 42 43 // 合法定义 44 inline BaseClass(const char* str): id(count++), name((char*)malloc(strlen(str))) 45 { 46 printf("基类构造函数! "); 47 strcpy(name, str); 48 data = 0; 49 } 50 inline ~BaseClass() 51 { 52 printf("基类析构函数! "); 53 54 // 以下语句导致基类析构函数卡住,不知道什么原因,这句话即使放到派生类中,也会导致派生类析构卡住,停止却不报错,很奇怪的现象~ 55 // 无论是new还是malloc的空间,都会卡住 56 // if (name) 57 // free(name); 58 59 // 即使用delete也会卡住 60 // delete name; 61 } 62 63 // 关于“虚函数是否能是static类型的问题” 64 // 下面的语句不合法! 65 // error C2216: “virtual”不能和“static”一起使用 66 // virtual static int doSomething() = 0; 67 68 // 合法定义,函数体为const类型 69 virtual int get_id() const {return id;} 70 virtual int get_max() const {return max;} 71 72 // 合法定义,传入的参数为const类型 73 virtual void set_data(const int& d){data = d;} 74 75 // 关于“const修饰的成员函数的问题” 76 // 下面的语句不合法! 77 // error C3490: 由于正在通过常量对象访问“data”,因此无法对其进行修改 78 // 有const修饰时,类的全部成员变量变成了const类型 79 // 例如:const char* name 会变成 const char* const name; int data 变成了 const int data; 80 // virtual void set_data(const int& d) const {data = d;} 81 82 // 合法定义 83 virtual void print_string() const { 84 printf("My id is %d , my name is %s and my data is %d. ", id, name, data); 85 } 86 87 }; 88 89 // 下面的语句不合法! 90 // error C2720: “BaseClass::cnt”: 成员上的“static ”存储类说明符非法 91 // static int BaseClass::cnt = 0; 92 93 // 合法赋值表达式,必须有类型说明:int,否则不合法 94 int BaseClass::count = 1; 95 96 // 下面的语句不合法! 97 // error C2373: “max”: 重定义;不同的类型修饰符 98 // int BaseClass::max = 1024; 99 100 // 合法赋值表达式,必须同时有const和int 101 const int BaseClass::max = 1024; 102 103 class DerivedClass : public BaseClass 104 { 105 private: 106 char* subname; 107 public: 108 // 由于基类没有默认构造函数,子类必须定义构造函数,而且必须是对应参数及类型的构造函数,否则出现错误: 109 // error C2512: “DerivedClass”: 没有合适的默认构造函数可用 110 // error C2512: “BaseClass”: 没有合适的默认构造函数可用 111 // DerivedClass(){}; 112 113 // 下面的语句没有意义,相当于创建的一个临时变量,语句结束即销毁 114 // DerivedClass(const char* str){BaseClass(str);}; 115 116 // 合法定义 117 DerivedClass(const char* str):BaseClass(str) 118 { 119 printf("派生类构造函数! "); 120 subname = NULL; 121 }; 122 123 ~DerivedClass() 124 { 125 printf("派生类析构函数! "); 126 127 // 以下语句会导致delete操作时卡住,不知道为什么,很奇怪~ 128 // if (subname) 129 // free(subname); 130 // subname = NULL; 131 132 // 下面的语句同上,莫名其妙的卡住 133 // delete subname; 134 135 } 136 137 void set_sub_name(const char* str) 138 { 139 if(subname) 140 free(subname); 141 subname = new char[strlen(str)]; 142 strcpy(subname, str); 143 } 144 145 void print_string() const 146 { 147 // 下面的语句不合法! 148 // 因为id是private类型,不能被子类访问 149 // 而protected类型可以,例如name和data 150 // error C2248: “BaseClass::id”: 无法访问 private 成员(在“BaseClass”类中声明) 151 // printf("My id is %d , my name is %s and my data is %d. ", id, name, data); 152 153 // 下面的语句不合法 154 // 因为有const修饰的函数无法调用派生类和基类的非const类型的函数 155 // error C2662: “BaseClass::set_data”: 不能将“this”指针从“const DerivedClass”转换为“BaseClass &” 156 // set_data(1); 157 158 // 合法调用 159 BaseClass::print_string(); 160 161 // 合法调用 162 // const修饰的函数只能调用派生类和基类的const函数,下面的Base::get_id()便是一个有const修饰的函数 163 // 这是派生类的const函数访问基类的private函数的唯一方法,访问他们的const类型的get函数,但是显然const类型的函数无法修改private类型的变量,也无法修改其他类型的变量 164 printf("I'm a DerivedClass, my subname is %s and I can see max = %d. ", subname, BaseClass::get_max()); 165 166 }; 167 }; 168 169 int main() 170 { 171 172 { 173 // 测试构造函数的顺序 174 printf(">> 构造函数顺序依次是: "); 175 DerivedClass a("Liu"); 176 printf("<< 测试结束! "); 177 a.print_string(); 178 printf(">> 析构函数顺序依次是: "); 179 // 测试析构函数的顺序 180 } 181 printf("<< 测试结束! "); 182 DerivedClass* b = new DerivedClass("Wang"); 183 b->set_sub_name("Jone"); 184 b->print_string(); 185 // 测试free能否出发析构函数 186 printf(">> 测试free能否触发析构函数: "); 187 free(b); 188 printf("<< 测试结束! "); 189 b = NULL; 190 191 // 测试delete能否触发析构函数 192 DerivedClass* c = new DerivedClass("Zhao"); 193 c->set_sub_name("Mike"); 194 c->print_string(); 195 printf(">> 测试delete能否触发析构函数: "); 196 delete c; 197 printf("<< 测试结束! "); 198 c = NULL; 199 200 // 合法,释放堆中的空间 201 int* arr1 = new int[10]; 202 free(arr1); 203 204 // 语法合法,但执行非法,通过free释放栈中的空间 205 // int arr2[10] = {0}; 206 // free(arr2); 207 208 // 语法合法,但执行非法,通过free释放常量区的空间 209 // char* arr3 = "Hello !"; 210 // free(arr3); 211 212 getchar(); 213 return 0; 214 }
输出结果是:
>> 构造函数顺序依次是: 基类构造函数! 派生类构造函数! << 测试结束! My id is 1 , my name is Liu and my data is 0. I'm a DerivedClass, my subname is (null) and I can see max = 1024. >> 析构函数顺序依次是: 派生类析构函数! 基类析构函数! << 测试结束! 基类构造函数! 派生类构造函数! My id is 2 , my name is Wang and my data is 0. I'm a DerivedClass, my subname is Jone and I can see max = 1024. >> 测试free能否触发析构函数: << 测试结束! 基类构造函数! 派生类构造函数! My id is 3 , my name is Zhao and my data is 0. I'm a DerivedClass, my subname is Mike and I can see max = 1024. >> 测试delete能否触发析构函数: 派生类析构函数! 基类析构函数! << 测试结束!