11300
备注:
|
14263
|
删除的内容标记成这样。 | 加入的内容标记成这样。 |
行号 6: | 行号 6: |
* C++语言只提供了整数、浮点数、bool、字符等基本类型。如何处理系统没有内置的类型?比如复数?时间?日期?坐标? 传统C语言的做法: |
C++语言只提供了整数、浮点数、bool、字符等基本类型。如何处理系统没有内置的类型?比如复数?时间?日期?坐标?传统C语言的做法是使用结构体,比如: |
行号 19: | 行号 17: |
另一个例子: | |
行号 36: | 行号 35: |
* C++的做法:将函数与数据结合在一起,构成类class | C++的做法是在C语言的基础上更进一步,将数据与操作这组数据的函数结合在一起,构成类(class) |
行号 115: | 行号 114: |
成员函数和普通函数一样可以内联、重载、带默认值。函数体写在类定义内部的成员函数,默认就是内联的。 | 成员函数和普通函数一样可以内联。函数体写在类定义内部的成员函数,默认就是内联的。 |
行号 124: | 行号 123: |
行号 131: | 行号 131: |
成员函数也可以重载 | |
行号 136: | 行号 136: |
hour = h; minute = m; second = 0; | hour = h; minute = m; second = 0; |
行号 139: | 行号 141: |
hour = h; minute = second = 0; | hour = h; minute = second = 0; |
行号 149: | 行号 152: |
成员函数也可以有缺省参数 | |
行号 305: | 行号 309: |
== 对象的复制 == | == 对象的拷贝构造 == |
行号 400: | 行号 404: |
== 类的组合 == 构造复杂的对象的一种方法是组合。一个类可以使用另一个类的对象作为成员,比如: {{{#!cplusplus class point{ private: double x, y; public: //... }; class line { private: point start, end; public: //... }; class circle { private: point center; double radius; public: //... }; class rectangle { private: point p1, p2; public: //... }; }}} 组合对象的构造 {{{#!cplusplus class point{ public: double x, y; point(double x0 = 0, double y0 = 0) { x = x0; y = y0; cout << "point " << x << y << "initialized!" << endl; } }; class line { public: point start, end; line(double x0, double y0, double x1, double y1) { cout << "line initializing" << endl; start.x = x0; start.y = y0; end.x = x1; end.y = y1; } }; }}} 从这个程序的运行结果可以看出,在line类的构造函数执行前,start和end对象已经构造完成。point类没有默认构造函数,line不能构造。如果x、y是私有的,那么在line构造函数中不能对他们进行赋值。解决办法:使用构造函数初始化列表 {{{#!cplusplus class point{ private: double x, y; public: point(double x0, double y0) { x = x0; y = y0; cout << "point " << x << y << "initialized!" << endl; } }; class line { private: point start, end; public: line(double x0, double y0, double x1, double y1) : start(x0, y0), end(x1, y1) { cout << "line initializing" << endl; } }; }}} 在line构造函数的初始化列表中,给start、end成员的构造函数传递参数完成它们的初始化。 初始化表还能够解决其它一些类型的成员的初始化问题,比如const成员,引用成员等。比如 {{{#!cplusplus class C { public: C(int h, int m, int s) : s ( 0 ), x( 0 ), time(h, m, s), t(time) { } private: int x; const int s; //const data member Clock time; // no default construct Clock &t; // reference member }; }}} 构造函数和析构函数执行的顺序 {{{#!cplusplus class point{ private: double x, y; public: point(double a, double b) :x(a), y(b) { cout << "construct point" << endl; } ~point() { cout << "destruct point" << endl; } }; class line { private: point start, end; public: line(double x0, double y0, double x1, double y1) : start(x0, y0) , end(x1, y1) { cout << "construct line" << endl; } ~line() { cout << "destruct line" << endl; } }; }}} = The End = |
C++类与对象
1. 问题
C++语言只提供了整数、浮点数、bool、字符等基本类型。如何处理系统没有内置的类型?比如复数?时间?日期?坐标?传统C语言的做法是使用结构体,比如:
另一个例子:
2. C++的类
C++的做法是在C语言的基础上更进一步,将数据与操作这组数据的函数结合在一起,构成类(class)
C++中类的定义可以用struct或者用class。函数与数据结合在一起,逻辑关系更加明确。类中的函数又被称为方法、成员函数。C++类中函数的定义,函数体可以直接写在类的内部,写在头文件中:
也可以分开定义,比如:
1 //clock.h头文件:
2 struct Clock {
3 int hour, minute, second;
4 void SetTime(int h, int m, int s);
5 void ShowTime();
6 };
7
8 //clock.cpp源文件:
9 void Clock::SetTime(int h, int m, int s) {
10 hour = h;
11 minute = m;
12 second = s;
13 }
14 void Clock::ShowTime() {
15 cout << hour << minute << second;
16 }
对象的定义和访问方式类似于结构体
在堆空间分配和访问对象
定义对象数组
成员函数和普通函数一样可以内联。函数体写在类定义内部的成员函数,默认就是内联的。
类外定义函数体的成员函数,要定义成内联需要加inline关键字,并把函数体写在头文件中
成员函数也可以重载
成员函数也可以有缺省参数
3. 类的访问权限
公有部分定义了类的外部接口,可供类的使用者调用。私有部分隐藏了类的具体实现,由类的实现者实现,不需要使用者关心。这就是封装。private和public为新增的关键字。
struct与class的访问权限的区别:struct默认public,class默认为private
4. 构造与析构
定义变量的同时完成初始化(resource acquisition is initialization)是一种好的编程习惯,可以避免错误。
为避免偶然使用没有初始化的对象的错误,可以在类中定义一个特殊的函数——构造函数。它在对象被定义时,就被自动调用,以确保完成初始化。
构造函数的名字与类名相同,没有返回类型。它利用特定的值构造对象,把对象初始化为一个特定的状态。
带构造函数的对象定义
构造函数可以重载,也可以有缺省参数:
各个构造函数所需要参数不同,但构造函数都没有返回类型。在定义对象时,会根据传递的参数来选择一个特定的构造函数初始化对象。
一个类要能够默认构造对象,需要:这个类一个构造函数都没有写(系统会自动生成一个默认构造函数),或者至少写有一个默认构造函数。一个所有参数具有默认参数的构造函数也是默认构造函数,比如
对象被摧毁时,一个成员函数也会自动被调用,这个函数称为称为析构函数,一般完成资源的释放工作
析构函数的名字为类名前加~,没有返回类型和参数。析构函数不能重载。例如:
new会自动调用构造函数,而malloc不能。delete会自动调用析构函数,而free不能。
要定义对象数组,并且没有初始化,那么要求该类可以默认构造对象。比如:
5. 对象的拷贝构造
对象在两种情况下发生复制:赋值和拷贝构造。拷贝构造是指创建一个对象,创建的同时让它的值与另一个已存在的对象一模一样。赋值是复制另一个同类型的值给已存在的对象,使它变成新的值。比如
拷贝构造的工作由拷贝构造函数完成。如果自己没有编写拷贝构造函数,编译器会自动生成一个拷贝构造函数,用于完成缺省的拷贝构造的功能:用源对象的所有数据成员逐一拷贝构造目标对象的相应成员。我们可以自定义拷贝构造函数去改写默认的拷贝构造函数。
何时需要自定义拷贝构造函数、析构函数?当涉及到内存管理时,一个类中有指针成员,指向动态分配的空间,那么通常需要写一组拷贝构造函数、析构函数和赋值操作符。写一个类Array,模拟数组的功能,元素是int类型,数组的大小可以是变量,增加检查越界的功能。即可以这样使用:
但是这个类在这样使用时存在问题:
拷贝构造的对象与原对象共享同一块空间,修改了一个对象,另一个对象也受影响。当一个对象释放时,另一个对象也不能使用了。当两个对象都被释放时,同一个空间释放了两次。解决办法是自定义拷贝构造函数:
1 class Array {
2 private:
3 int *p;
4 int size;
5 public:
6 Array(int s) {
7 size = s;
8 p = new int [ size ];
9 }
10 ~Array() {
11 delete[ ] p;
12 }
13 int & at( int i) {
14 if( i < size)
15 return p[i];
16 else
17 return 0;
18 }
19 Array( Array &a) {
20 size = a.size;
21 p = new int [size];
22 for(int i = 0; i < size; i++)
23 p[i] = a.p[i];
24 }
25 };
6. 类的组合
构造复杂的对象的一种方法是组合。一个类可以使用另一个类的对象作为成员,比如:
1 class point{
2 private:
3 double x, y;
4 public:
5 //...
6 };
7
8 class line {
9 private:
10 point start, end;
11 public:
12 //...
13 };
14
15 class circle {
16 private:
17 point center;
18 double radius;
19 public:
20 //...
21 };
22
23 class rectangle {
24 private:
25 point p1, p2;
26 public:
27 //...
28 };
组合对象的构造
1 class point{
2 public:
3 double x, y;
4 point(double x0 = 0, double y0 = 0) {
5 x = x0;
6 y = y0;
7 cout << "point " << x << y << "initialized!" << endl;
8 }
9 };
10
11 class line {
12 public:
13 point start, end;
14 line(double x0, double y0, double x1, double y1) {
15 cout << "line initializing" << endl;
16 start.x = x0;
17 start.y = y0;
18 end.x = x1;
19 end.y = y1;
20 }
21 };
从这个程序的运行结果可以看出,在line类的构造函数执行前,start和end对象已经构造完成。point类没有默认构造函数,line不能构造。如果x、y是私有的,那么在line构造函数中不能对他们进行赋值。解决办法:使用构造函数初始化列表
1 class point{
2 private:
3 double x, y;
4 public:
5 point(double x0, double y0) {
6 x = x0;
7 y = y0;
8 cout << "point " << x << y << "initialized!" << endl;
9 }
10 };
11
12 class line {
13 private:
14 point start, end;
15 public:
16 line(double x0, double y0, double x1, double y1)
17 : start(x0, y0), end(x1, y1) {
18 cout << "line initializing" << endl;
19 }
20 };
在line构造函数的初始化列表中,给start、end成员的构造函数传递参数完成它们的初始化。
初始化表还能够解决其它一些类型的成员的初始化问题,比如const成员,引用成员等。比如
构造函数和析构函数执行的顺序
1 class point{
2 private:
3 double x, y;
4 public:
5 point(double a, double b) :x(a), y(b) {
6 cout << "construct point" << endl;
7 }
8 ~point() {
9 cout << "destruct point" << endl;
10 }
11 };
12 class line {
13 private:
14 point start, end;
15 public:
16 line(double x0, double y0, double x1, double y1)
17 : start(x0, y0) , end(x1, y1) {
18 cout << "construct line" << endl;
19 }
20 ~line() {
21 cout << "destruct line" << endl;
22 }
23 };