this指针
在写类和对象时会遇见一个问题,一个类可以创建出多个对象,这些对象的成员变量都是一样的。成员函数需要对这些成员变量进行操作,往往需要传参,这时候就涉及到一个取名的问题。如果取到一样,就不能进行区分。但是如果都取不一样的名字,取名字这件事就会变得很困难(当一个游戏不允许重名时,想了几个名字都重复的痛,谁懂啊)。
C++引入了this指针来解决这一问题。C++编译器给每个非静态的成员函数增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,不需要用户来传递,编译器就可以自动完成。
class Date { public: void Init(int year, int month, int day) { /*this->_year = year; this->_month = month; this->_day = day;*/ //this指针一般不会显示的写出来 _year = year; _month = month; _day = day; } void Printf() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; int main() { Date d1, d2; d1.Init(2023, 3, 2); d2.Init(2023, 3, 1); d1.Printf(); d2.Printf(); return 0; }
this指针的特性
this指针是被const修饰的,即成员函数中,不能给this指针赋值;
this指针只能够在成员函数中使用;
this指针本质上是成员函数的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针;
this指针是成员函数第一个隐含的指针形参,一班情况由编译器通过ecx寄存器自动传递,不需要用户传递。
C++和C的一些区别
C++:
数据和方法都封装到类里面;
控制访问方式,需要公开使用的就设为公有,不需要访问的就设为私有;
C:
数据和方法分离;
数据访问控制是自由,不受限制的。
类的6个默认成员函数
如果一个类中什么成员都没有,就被简称为空类。实际上空类并非是什么都没有,任何一个类在什么都不写是,编译器会自动生成6个默认成员函数。由编译器生成的成员函数,且用户没有显示的实现,就被称为默认成员函数。
初始化和清理:
构造函数主要完成初始化工作;
析构函数主要完成清理工作;
拷贝复制:
拷贝构造是使用同类对象初始化创建对象;
赋值重载主要是把一个对象赋值给另一个对象;
取地址重载:
主要是普通对象和const对象取地址,这两个很少会自己实现。
构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。构造函数的主要任务是初始化对象。
特征
函数名与类名相同;
无返回值,并非指是void类型;
对象实例化时编译器自动调用对应的构造函数;
构造函数可以重载,即一个类可以有多个构造函数;
class Date { public: Date() { _year = 2000; _month = 1; _day = 1; } Date(int year, int month, int day) { _year = year; _month = month; _day = day; } void Print() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; int main() { Date d1; Date d2(2023, 3, 2); //无参构造函数创建对象时不能带(),否则会报错 //Date d3(); d1.Print(); d2.Print(); return 0; }
如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不在生成默认构造函数。
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,自定义类型就是我们自己定义的类型。默认生成的函数不对内置类型成员做处理,自定义类型的成员会去调用它的默认构造函数。
class Time { public: Time() { cout << "Time()" << endl; _hour = 0; _minute = 0; _second = 0; } private: int _hour; int _minute; int _second; }; class Date { public: void Print() { cout << _year << "年" << _month << "月" << _day << "日" << endl; } private: // 基本类型(内置类型) // 之后在C++11中打了补丁,允许内置成员变量在类中声明时设定默认值 int _year; int _month; int _day; // 自定义类型 Time _t; }; int main() { Date d; d.Print(); return 0; }
析构函数
析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象的销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
特征
析构函数名是在类名前加上字符~;
无参数无返回值类型;
一个类只能有一个析构函数。若为显示定义,系统会自动生成默认的析构函数。析构函数不能够重载;
对象生命周期结束时,C++编译系统自动调用析构函数;
typedef int DataType; class Stack { public: Stack(size_t capacity = 3) { _array = (DataType*)malloc(sizeof(DataType) * capacity); if (NULL == _array) { perror("malloc申请空间失败!"); exit(-1); } _capacity = capacity; _size = 0; } void Push(DataType data) { _array[_size] = data; _size++; } ~Stack() { if (_array) { free(_array); _array = NULL; _capacity = 0; _size = 0; } } private: DataType* _array; int _capacity; int _size; }; void TestStack() { Stack s; s.Push(1); s.Push(2); } int main() { TestStack(); return 0; }
析构函数和构造函数一样,默认生成的函数不对内置类型成员做处理,自定义类型的成员会去调用它的默认析构函数。
class Time { public: ~Time() { cout << "~Time()" << endl; } private: int _hour; int _minute; int _second; }; class Date { private: // 基本类型(内置类型) int _year = 1970; int _month = 1; int _day = 1; // 自定义类型 Time _t; }; int main() { Date d; return 0; }
如果类没有申请资源,析构函数可以不写,直接使用编译器生成的默认析构函数。如果有资源申请,就一定要写,否则会造成资源泄漏。