C++类与对象
1. 问题
- C++语言只提供了整数、浮点数、bool、字符等基本类型。如何处理系统没有内置的类型?比如复数?时间?日期?坐标?
传统C语言的做法:
1 struct complex {
2 double real;
3 double imag;
4 };
5 complex add(complex a, complex b);
6 complex substract(complex a, complex b);
7 complex multiply(complex a, complex b);
1 struct Clock {
2 int second;
3 int minute;
4 int hour;
5 };
6 void SetTime( Clock *c, int h, int m, int s) {
7 c->second = s;
8 c->minute = m;
9 c->hour = h;
10 }
11 void ShowTime( Clock *c) {
12 cout << c->hour << c->minute << c->second;
13 }
2. C++的类
- C++的做法:将函数与数据结合在一起,构成类class
1 struct Clock {
2 int hour, minute, second;
3 void SetTime(int h, int m, int s);
4 void ShowTime();
5 };
C++中类的定义可以用struct或者用class。函数与数据结合在一起,逻辑关系更加明确。类中的函数又被称为方法、成员函数。C++类中函数的定义,函数体可以直接写在类的内部,写在头文件中:
1 struct Clock {
2 int hour, minute, second;
3 void SetTime(int h, int m, int s) {
4 hour = h; minute = m; second = s;
5 }
6 void ShowTime() {
7 cout << hour << minute << second;
8 }
9 };
也可以分开定义,比如:
1
2 struct Clock {
3 int hour, minute, second;
4 void SetTime(int h, int m, int s);
5 void ShowTime();
6 };
7
8
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 }
对象的定义和访问方式类似于结构体
1 int main() {
2 struct Clock now;
3 Clock next;
4 next.hour = 0;
5 now.SetTime(9, 40, 0);
6 now.ShowTime();
7 next.SetTime(9, 40, 1);
8 next.ShowTime();
9 }
在堆空间分配和访问对象
1 void f() {
2 Clock * my_clock = new Clock;
3 my_clock->hour = 10;
4 my_clock->SetTime (9, 40, 0);
5 my_clock->ShowTime();
6 delete my_clock;
7 }
定义对象数组
1 int main() {
2 Clock clocks[100];
3 clocks[0].SetTime(9, 10, 25);
4 clocks[1].SetTime(9, 9, 13);
5 clocks[2].SetTime(9, 12, 25);
6
7 Clock *pc = new Clock[100];
8 pc[0].SetTime(11, 20, 30);
9
10 }
成员函数和普通函数一样可以内联、重载、带默认值。函数体写在类定义内部的成员函数,默认就是内联的。
1 struct Clock {
2 int second, minute, hour;
3 inline void ShowTime() {
4 cout << hour << minute << second;
5 }
6 };
类外定义函数体的成员函数,要定义成内联需要加inline关键字,并把函数体写在头文件中
1 inline void Clock::ShowTime() {
2 cout << hour << minute << second;
3 }
1 struct Clock {
2 int second, minute, hour;
3 void SetTime(int h, int m) {
4 hour = h; minute = m; second = 0;
5 }
6 void SetTime(int h) {
7 hour = h; minute = second = 0;
8 }
9 };
10 int main() {
11 Clock t;
12 t.SetTime( 10, 30);
13 t.SetTime( 10 );
14 }
1 struct Clock {
2 int second, minute, hour;
3 void SetTime(int h =0, int m=0, int s=0);
4 };
5 void Clock::SetTime(int h, int m, int s) {
6 hour = h; minute = m; second = s;
7 }
3. 类的访问权限
1 class Clock {
2 private:
3 int hour, minute, second;
4 public:
5 void SetTime(int yy, int mm, int dd);
6 void ShowTime();
7 };
公有部分定义了类的外部接口,可供类的使用者调用。私有部分隐藏了类的具体实现,由类的实现者实现,不需要使用者关心。这就是封装。private和public为新增的关键字。
1 int main(){
2 Clock d;
3 d.SetTime(8, 27, 0);
4 d.hour = 10;
5 }
6 void Clock::SetTime(int h, int m, int s) {
7 hour = h;
8 minute = m;
9 second = s;
10 }
struct与class的访问权限的区别:struct默认public,class默认为private
1 struct ClockA {
2 void SetTime(int yy, int mm, int dd);
3 };
4
5 class ClockB {
6 int hour, minute, second;
7 };
4. 构造函数constructor
定义变量的同时完成初始化(resource acquisition is initialization)是一种好的编程习惯,可以避免错误。
1 int i = 5;
2 cout << i;
3 Clock time;
4 time.ShowTime();
5 time.SetTime(2000, 5, 1);
6 time.ShowTime();
7
为避免偶然使用没有初始化的对象的错误,可以在类中定义一个特殊的函数——构造函数。它在对象被定义时,就被自动调用,以确保完成初始化。
1 class Clock{
2 public:
3 Clock(int h, int m, int s);
4 };
构造函数的名字与类名相同,没有返回类型。它利用特定的值构造对象,把对象初始化为一个特定的状态。
1 Clock::Clock( int h, int m, int s) {
2 hour = h; minute = m; second = s;
3 }
带构造函数的对象定义
1 int main() {
2 Clock now;
3 Clock getup(6, 30, 30);
4 Clock now = Clock(9, 21, 20);
5 Clock *pC = new Clock(23, 30, 25);
6 }
构造函数可以重载,也可以有缺省参数:
1 class Clock {
2 int hour, minute, second;
3 public:
4 Clock(int h, int m=0, int s=0);
5 Clock();
6 Clock(const char *);
7 void Clock ();
8 };
各个构造函数所需要参数不同,但构造函数都没有返回类型。在定义对象时,会根据传递的参数来选择一个特定的构造函数初始化对象。
1 int main() {
2 Clock now;
3 Clock getup(6, 30, 30);
4 Clock now = Clock(9, 21);
5 Clock *pC = new Clock("23:30:0");
6 }
一个类要能够默认构造对象,需要:这个类一个构造函数都没有写(系统会自动生成一个默认构造函数),或者至少写有一个默认构造函数。一个所有参数具有默认参数的构造函数也是默认构造函数,比如
1 class Clock {
2 int hour, minute, second;
3 public:
4 Clock(int h =0, int m = 0, int s=0);
5 };
对象被摧毁时,一个成员函数也会自动被调用,这个函数称为称为析构函数,一般完成资源的释放工作
1 class Clock {
2 int hour, minute, second;
3 public:
4 ~Clock();
5 };
析构函数的名字为类名前加~,没有返回类型和参数。析构函数不能重载。例如:
1 int main() {
2 Clock d1(4, 11, 1);
3 if( true ){
4 Clock *d2 = new Clock(9, 9, 9);
5 Clock d3(8, 10,0);
6
7 }
8 delete d2;
9 Clock d4;
10 }
11
new会自动调用构造函数,而malloc不能。delete会自动调用析构函数,而free不能。
1 int main() {
2 Clock *d1 = new Clock ;
3 Clock *d2 = new Clock ( 10, 11, 1);
4 Clock *d3 = new Clock [ 1000 ];
5 Clock *d4 = (Clock *)malloc( sizeof(Clock) );
6 delete d1;
7 delete d2;
8 delete[ ] d3;
9 free(d4);
10 }
要定义对象数组,并且没有初始化,那么要求该类可以默认构造对象。比如:
1 void f() {
2 Clock cls[10];
3 Clock *p = new Clock[10];
4 }