340 likes | 494 Views
第十讲 类与对象(二). 内容提要. 对象的生存期 静态成员 友元 常对象 对象数组与对象指针 向量类: vector 字符串类: string. 生存期与作用域. 对象生存期: (与普通变量相同). 静态生存期:生存期与程序的运行期相同,即一直有效 动态生存期:当对象所在的程序块执行完后即消失. 全局对象:静态生存期 动态对象:动态生存期. 类的数据成员的作用域(称为 类作用域 ). 数据成员可以被类中的所有函数成员访问(类似全局变量) 成员函数中声明的变量是局部变量
E N D
内容提要 • 对象的生存期 • 静态成员 • 友元 • 常对象 • 对象数组与对象指针 • 向量类: vector • 字符串类:string
生存期与作用域 • 对象生存期:(与普通变量相同) • 静态生存期:生存期与程序的运行期相同,即一直有效 • 动态生存期:当对象所在的程序块执行完后即消失 • 全局对象:静态生存期 • 动态对象:动态生存期 • 类的数据成员的作用域(称为类作用域) • 数据成员可以被类中的所有函数成员访问(类似全局变量) • 成员函数中声明的变量是局部变量 • 如果成员函数中声明了与数据成员同名的变量,则数据成员被屏蔽
例:数据成员作用域 class Point //Point 类的声明 { public: //外部接口 Point(int a=0, int b=0) { x=a; y=b;} int Getx() {return x;} int Gety() {return y;} int p() { cout << x << endl; int x=5; cout << x;} private: // 私有数据 int x, y; }; int main() { Point A(4,5), B(8,0); A.p(); B.p(); return 0; } ex10_class_01.cpp
类的静态成员 • 静态数据成员 • 用关键字 static修饰 • 该类的所有对象共同使用和维护该成员 (这样就能实现不同对象之间的数据共享) • 必须在类外定义和初始化 • 静态数据成员的访问:类名::成员名 例: class Point { public: ... ... private: int x, y; static int count;// 引用性声明 }; int Point::count=0;// 静态数据成员的定义和初始化 ... ... 静态数据成员为整个类所共有,不属于任何特定对象。
静态函数成员 • 静态函数成员 • 用关键字 static修饰,为整个类所共有 • 没有目的对象,不能对非静态成员进行默认访问 • 一般通过“类名::函数成员名”来调用 • 静态函数成员可以直接访问该类的静态数据或函数成员(一般用于访问同一个类中的静态数据,维护对象之间共享的数据) 例: class A { public: ... ... static void f(A a); ... ... }; ... ...
类的友元 友元关系: 提供一种不同类或对象的函数成员之间、类的函数成员与一般函数之间进行数据共享的机制 通俗说法:一个类主动声明哪些类或函数是它的朋友,从而给它们提供对本类的访问特许,即可以访问私有成员和保护成员 • 友元提供了一种数据共享的方式,提高了程序效率和可读性 • 但友元在一定程度上破坏了数据封装和数据隐藏的机制 • 友元包括:友元函数与友元类 • 友元类的所有函数成员都是友元函数
友元函数 • 友元函数 • 用关键字 friend修饰 • 可以一个普通函数或其它类的函数成员 • 可以通过对象名访问私有成员和保护成员 例: class Point { public: ... ... friend float dist(Point & p1, Point & p2); private: int x, y; }; float dist(Point & p1, Point & p2) { double x=p1.x-p2.x, y=p1.y-p2.y; return sqrt(x*x+y*y); } ... ...
友元类 • 友元类 • 用关键字 friend修饰 • 友元类的所有函数成员都是友元函数 class A { public: ... ... friend class B; // 声明 B 是 A 的友元类 ... ... }; • 友元关系不能传递 • 友元关系是单向的 • 友元关系不能被继承
常对象 • 常对象 将对象声明成常对象,可以有效地保护数据 const类型说明符 对象名; 类型说明符 const 对象名; • 用关键字 const修饰 • 常对象必须进行初始化 • 常对象的值不能被改变 —数据成员:均为常量,不能被赋值 —函数成员:不能通过常对象调用普通成员函数!
常成员 • 常函数成员 类型说明符 函数名(形参) const; • 若一个对象是常对象,则通过该对象只能调用其常成员函数 • 无论对象是否为常对象,在常成员函数被调用期间,目的对象都将被视为常对象 • 常数据成员 • 将数据成员声明为常量 • 常引用 const类型说明符 & 引用名; • 常引用所引用的对象不能被更新 • 常引用可以绑定到常对象(普通引用不能)
内容提要 • 对象的生存期 • 静态成员 • 友元 • 常对象 • 对象数组与对象指针 • 向量类: vector • 字符串类:string
对象数组 • 对象数组 • 一维对象数组的声明 类名 数组名[n] • 一维对象数组的引用 数组名[k].成员名 • 初始化:对每个元素都调用构造函数 例: ... .. Point() { x=0; y=0} Point(int a, int b) { x=a; y=b; } ... ... int main() { Point A[2]={Point, Point(2,3)}; ... ...
对象指针 • 对象指针 对象指针:指向对象的指针,存放对象的地址 • 对象指针的声明 类名 * 对象指针名 例: Point a(1,2); Point * pa = &a; • 使用对象指针访问对象成员:“ -> ” 对象指针名->成员名 也可以使用普通方式,即: (*对象指针名).成员名
this 指针 this 指针:隐含在非静态成员函数中的特殊指针,指向目的对象 • this指针是常指针 • 当局部作用域中声明了与类成员同名的标识符(如变量名)时,可以通过 this指针访问该类的成员
例:this 指针 class Point //Point 类的声明 { public: //外部接口 Point(int a=0, int b=0) { x=a; y=b;} int Getx() {return x;} int Gety() {return y;} int p() {int x=5; cout << x; cout << this->x << endl; } void Setx(int x) { this->x=x; } private: // 私有数据 int x, y; }; ex10_class_02.cpp
指向成员的指针 指向成员指针:直接指向类的成员的指针 • 指向静态成员的指针 对类的静态成员的访问不依赖于对象,可以通过普通的指针来指向和访问静态成员 • 指向非静态成员的指针 类型说明符 类名::*指针名 // 指向数据成员 类型说明符 (类名::*指针名)(参数) // 指向函数成员
指向非静态成员 • 数据成员指针的赋值与引用 指针名 = &类名::数据成员名 对象名.*指针名 对象指针名->*指针名 • 函数成员指针的赋值与引用 指针名 = &类名::函数成员名 (对象名.*指针名)(参数) (对象指针名->*指针名)(参数)
创建动态对象 • 创建动态对象 类名 *指针名=new 类名() // 不带参数 类名 *指针名=new 类名(参数列表) // 带参数 • 程序结束后,动态对象会被释放,也可以用 delete 删除 delete 指针名
内容提要 • 对象的生存期 • 静态成员 • 友元 • 常对象 • 对象数组与对象指针 • 向量类: vector • 字符串类:string
向量类 C++提供了向量类,使用向量与使用数组一样,但向量的大小可以根据需要自动增长,比数组更灵活 • 向量的声明 vector <类型说明符> 向量名 例: 需要加库文件 vector #include <vector> ... ... vector <int> x; // 声明一个整型向量 • 这里定义的 x是对象,不是普通数组 • 向量的所有元素都会被初始化: - 若是基本数据类型,则全为零- 若是某个类的对象,则调用相应构造函数初始化- 也可以自己指定,此时所有元素只能指定相同的初值
vector • 向量元素的引用 向量名[下标] // 下标也是从 0 开始 • 向量的一个重要成员函数:size() 向量名.size() // 返回向量元素的个数 • 向量名不是地址!向量是封装了数组的对象 • 关于 vector 的更多介绍参见相关资料
字符串类 字符串:可以通过字符数组实现,也可以通过 string 类实现 • C++ 的 string 类提供了处理字符串的各种操作 • 使用 string 类必须包含 string 头文件 例: #include <string> // 注意不是 cstring ... ... string str; // 定义一个空字符串对象 string str1="Math.", str2("ECNU"); // 可以初始化 string str3=str1+str2; // str3="Math.ECNU" string str4(5,'c'); // 连续5 个字符 c
字符串类 • string 类构造函数原型 string(); // 默认构造函数 string(const string & s); // 复制构造函数 string(const char * s); // 用字符串常量初始化 string(const string & s, unsigned int p,unsigned int n); // 从位置 p 开始,取 n 个字符,即 s[p], .., s[p+n-1] string(const char * s, unsigned int n); // 使用前n个字符 string(unsigned int n, char c); // 将给定的字符重复n次
输入输出 • string 对象的输入输出 cin >> str cout << str • 输入 getline getline(cin,str) // 以换行符作为输入结束符 getline(cin,str,'c') // 将字符 'c' 作为输入结束符
基本操作 • string 类的基本操作 • 以上操作通过操作符重载实现 • 比较大小按字典顺序,从前往后逐个进行比较
基本操作 • string 对象的一些基本操作
基本操作举例 string str1="Hello"; string str2(3,'A'); string str3=str1 + " Math"; • 两个 string 对象可以相加 • string 对象和字符串也可以相加 • 但两个字符串不能直接相加 string str4="Hello" + " Math"; // ERROR string str4="Hello" + str2 + " Math"; // OK ex10_string01.cpp
基本操作举例 • string 对象可以直接赋值 • 但字符数组不能! string str1; char str2[10]; str1="Hello"; // OK str2="Hello"; // ERROR
更多成员函数 其它成员函数还有:max_size, swap, erase, clear, resize, replace, copy, compare等, 可参见 C++ Reference
课后练习 • 课后练习(自己练习) 教材第 267 页:10.14, 10.15
上机作业 1) 教材第 242 页,9.10,程序取名为 hw10_01.cpp 2) 教材第 268 页,10.1,程序取名为 hw10_02.cpp 3) 设计 Employee类,使用 string 对象,这个类包括: • 四个 string 类数据成员:name, addr, city, zip,分别表示姓名,街道地址,省市,邮编 • 一个带形参的构造函数,用于初始化数据成员 • 成员函数 ChangeName,修改姓名 • 成员函数 Display,输出所有信息(即姓名,地址,省市和邮编) • 数据成员是保护类型的,函数成员是公有类型的 实现这个类,并在主函数中测试这个类:使用你自己的相关信息初始化数据成员,并在屏幕上输出。 (可参考下页的模板,程序取名为 hw10_03.cpp)
上机作业 class Employee { public: Employee(string &, string &, string &, string &); void ChangeName(string &); void Display(); protected: string name; string addr; string city; string zip; };