第3章C+的类 3.1类的声明及定义 3.2访问权限 3.3内联及位段 3.4new和delete 3.5隐含参数this 3.6对象初始化 3.7类的存储空间
第3章 C++的类 3.1 类的声明及定义 3.2 访问权限 3.3 内联及位段 3.4 new和delete 3.5 隐含参数this 3.6 对象初始化 3.7 类的存储空间
3.1类的声明及定义
3.1 类的声明及定义
3.1类的声明及定义 类保留字: class、struct.或union可用来声明和 定义类。struct和union:是C原有的保留字,class 是C++新增加的 。 构造函数:是函数名和类名相同的函数成员 用于产生对象后初始化对象,如为对象申请内 存等。无返回类型,可以重载。 析构函数:是函数名和类名相同且带波浪线的 无参函数成员。用于销毁对象,销毁前先释放 对象申请的内存。无返回类型,不得重载。 如果类没有自定义的构造函数和析构函数,则 C++为类提供缺省的无参构造函数和析构函 数
3.1 类的声明及定义 类保留字:class、struct或union可用来声明和 定义类。struct和union是C原有的保留字,class 是C++新增加的。 构造函数:是函数名和类名相同的函数成员。 用于产生对象后初始化对象,如为对象申请内 存等。无返回类型,可以重载。 析构函数:是函数名和类名相同且带波浪线的 无参函数成员。用于销毁对象,销毁前先释放 对象申请的内存。无返回类型,不得重载。 如果类没有自定义的构造函数和析构函数,则 C++为类提供缺省的无参构造函数和析构函 数
13.1类的声明及定义 【例3.1】定义字符串类型和字符串对象。 #include struct STRING typedef char *CHARPTR; ∥定义类型成员 ■ CHARPTR s; ∥定义数据成员 ■ int strlen()片 ∥定义函数成员 ■ STRING(CHARPTR); ∥定义构造函数 ■ ~STRING()片 ∥定义析构函数 拐 int STRING:strlen() 用运算符:在类体外定义 for(int k=0;s[k]!=0;k++); ■ return k; ▣}
3.1 类的声明及定义 【例3.1】定义字符串类型和字符串对象。 #include struct STRING { typedef char *CHARPTR; //定义类型成员 CHARPTR s; //定义数据成员 int strlen( ); //定义函数成员 STRING(CHARPTR); //定义构造函数 ~STRING( ); //定义析构函数 }; int STRING::strlen( ) //用运算符::在类体外定义 { for(int k =0; s[k]!=0; k++); return k; }
3.1类的声明及定义 STRING:STRING(char *t) 用运算符:在类体外定义 for(int k=0;t[k]!=0;k++); s=(char *)malloc(k+1); ■ for(k=0;(s[k灯=t[k)=0;k++)月 ■ STRING:~STRING(){free(s;MI用运算符:在类体外定义 struct STRING x("simple"); void main(){ STRING y("complex"),*z=&y; int m=y.strlen(); m=z->strlen(); ■}
3.1 类的声明及定义 STRING::STRING(char *t) //用运算符::在类体外定义 { for(int k =0; t[k]!=0; k++); s=(char *)malloc(k+1); for(k=0; (s[k]=t[k])!=0; k++); } STRING::~STRING( ) { free(s); }//用运算符::在类体外定义 struct STRING x("simple"); void main( ){ STRING y("complex"), *z=&y; int m=y.strlen( ); m=z->strlen( ); }
13.1类的声明及定义 成员访问:,->,*,>*,:。其中:主 要用于访问基类或静态成员 构造函数:唯一不能被显式调用成员函 。定义该类的变量或常量时隐式调 用 析构函数:既能被显式调用,也能被隐 式调用。如果程序非正常退出,析构函 数隐式调用可能没机会执行,资源可能 没有释放。隐式调用在函数返回前调 用
3.1 类的声明及定义 成员访问:., ->, .*, ->*, ::。其中::主 要用于访问基类或静态成员。 构造函数:唯一不能被显式调用成员函 数。定义该类的变量或常量时隐式调 用。 析构函数:既能被显式调用,也能被隐 式调用。如果程序非正常退出,析构函 数隐式调用可能没机会执行,资源可能 没有释放。隐式调用在函数返回前调 用
3.1类的声明及定义 exit退出:隐式调用的析构函数不能执行。局部 对象的资源不能被释放,全局对象的资源可以被 释放,即exit退出main后执行收工函数。 abot退出:隐式调用的析构函数不能执行。局 部和全局对象的资源都不能被释放,即abort退出 main后不执行收工函数。 return返回:隐式调用的析构函数得以执行。局 部和全局对象的资源被释放。提倡使用return。 void main(...if (error)return;... n 如果用abot和exit,则要显式调用析构函数。 ·使用异常处理,隐式调用的析构函数会执行
3.1 类的声明及定义 exit退出:隐式调用的析构函数不能执行。局部 对象的资源不能被释放,全局对象的资源可以被 释放,即exit退出main后执行收工函数。 abort退出:隐式调用的析构函数不能执行。局 部和全局对象的资源都不能被释放,即abort退出 main后不执行收工函数。 return返回:隐式调用的析构函数得以执行。局 部和全局对象的资源被释放。提倡使用return。 void main( ){ …; if (error) return; …;} 如果用abort和exit,则要显式调用析构函数。 使用异常处理,隐式调用的析构函数会执行
3.1类的声明及定义 反复析构:同一对象的析构函数被反复 调用。Unix,Windows的内存释放可以反 复进行,但某些资源如设备、文件不能 反复析构。例如,既显式调用又隐式调 用析构函数导致反复析构。 解决方案:对象内部成员设置标志,如 可利用指针是否为空判断内存是否已经 释放。释放完毕立即置空标志
3.1 类的声明及定义 反复析构:同一对象的析构函数被反复 调用。Unix, Windows的内存释放可以反 复进行,但某些资源如设备、文件不能 反复析构。例如,既显式调用又隐式调 用析构函数导致反复析构。 解决方案:对象内部成员设置标志,如 可利用指针是否为空判断内存是否已经 释放。释放完毕立即置空标志
3.1类的声明及定义 【例3.3】定义能防止反复析构的字符串类。 #include #include #include struct STRING ■ char *s; STRING(char *) ~STRING(); : ■ STRING:STRING(char *t) ■ s=(char *)malloc(strlen(t)+1); strcpy(s,t); cout<<"CONSTRUCT:"<<sj }
3.1 类的声明及定义 【例3.3】定义能防止反复析构的字符串类。 #include #include #include struct STRING{ char *s; STRING(char *); ~STRING( ); }; STRING::STRING(char *t){ s=(char *)malloc(strlen(t)+1); strcpy(s,t); cout<<"CONSTRUCT: "<<s; }
3.1类的声明及定义 STRING::~STRING( ifs==0)return;//去掉本行,s1析构两次 cout<<"DECONSTRUCT:"<<s; ■ free(s);s=0; //在析构后置析构标志 ■ void main(void) STRING s1("String varible 1\n"); STRING s2("String varible 2\n"); STRING("Constant\n"); cout<<"RETURN\n";
3.1 类的声明及定义 STRING::~STRING( ){ if(s==0) return; //去掉本行,s1析构两次 cout<<"DECONSTRUCT: "<<s; free(s); s=0; //在析构后置析构标志 } void main(void){ STRING s1("String varible 1\n"); STRING s2("String varible 2\n"); STRING("Constant\n"); cout<< "RETURN\n"; }