概述
目录
隐藏的this指针
默认成员函数
1.类的6个默认成员函数
①构造函数
②析构函数
③拷贝构造函数
④赋值运算符重载
⑤const成员
隐藏的this指针
#include<iostream>
using namespace std;
class Date
{
public:
//编译会增加一个隐含的参数->void Init(Date* this,int year,int month,int day)
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
//哪个对象去调用成员函数,成员函数中访问的就是哪个对象中的成员变量,是通过this指针来做到的
Date d1;
d1.Init(2021, 6, 14);//d1.Init(&d1,2021,6,14)
Date d2;
d2.Init(2021, 6, 15);//d2.Init(&d2,2021,6,15)
return 0;
}
这里的Init函数实际上是这样的
void Init(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
注意:
1.this指针是隐含的,是编译器编译时加的,我们不能显式地在调用和定义中加上,例如写调用函数时写成这样是错的:d1.Init(&d1,2021,6,14)
2.可以在成员函数中使用this指针,例如第二张图
3.this一般是存在栈上的,不同的编译器不同,vs是使用ecx寄存器存储,传参
来看一个经典问题
1.下面程序能编译通过吗?
2.下面程序会崩溃吗?在哪里崩溃
#include<iostream>
using namespace std;
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
void Show()
{
cout << "Show()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
p->Show();
return 0;
}
先说答案:
p->PrintA()和p->Show()都可以编译通过,但是前者会崩溃,后者却会正常打印。
为什么呢?p不是一个空指针吗,为什么第一个打印就会报对空指针访问的错误,第二个打印会正常运行呢?
原因如下
还是this指针的原因
第一个成员函数中接收到的this是空指针,这句cout << _a << endl相当于cout << this->_a << endl
要打印_a就要对空指针进行访问,所以会崩溃
而p->Show()这个函数,这里没有对p这个指针解引用,所以这里不会引发空指针访问的崩溃
默认成员函数
类里面成员函数我们什么都不写的时候,编译器会自动生成6个函数,这6个函数就叫做默认成员函数
就像下面这样
#include<iostream>
using namespace std;
//类里面成员函数我们什么都不写的时候,编译器会自动生成6个函数,这6个函数就叫做默认成员函数
class Date
{
private:
int _year;
int _month;
int _day;
};
int main()
{
return 0;
}
1.类的6个默认成员函数
如果一个类中什么成员也没有,简称空类。空类就什么都没有吗?并不是的,任何一个类在我们不写的情况下,都会自动生成下面6个默认成员函数
下面我会逐个解释
①构造函数
特性:构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是它的主要任务并不是开空间创建对象,而是初始化对象
其特征如下:
1.函数名与类名相同
2.无返回值
3.对象实例化时编译器自动调用对应的构造函数(意思就是你不用手动调用这个函数,当你用类创建出一个对象时,构造函数会被自动调用)
4.构造函数可以重载
#include<iostream>
using namespace std;
class Date
{
public:
//构造函数
Date(int year, int month, int day);
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2021, 6, 15);//创建出一个对象时自动调用
return 0;
}
一般常见的是写一个全缺省的构造函数,好用
#include<iostream>
using namespace std;
class Date
{
public:
//构造函数
Date(int year = 2021, int month = 1, int day = 1);
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2021, 6, 15);
Date d2;//2021 1 1
return 0;
}
而且,若我们不写,编译器会自动生成一个构造函数,我们写了编译器就不会生成了。所以说构造函数叫默认成员函数。
总结:一般情况建议写一个全缺省的构造函数,这种方式能适应各种场景
②析构函数
概念:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象的销毁工作是由编译器完成的,而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作。
特征:
1.析构函数名是在类名前面加上字符~
2.无参数无返回值
3.一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数
4.对象生命周期结束时,c++编译系统自动调用析构函数
析构顺序
试问st1和st2谁先析构呢?
答案是st2
因为对象是定义在函数中的,函数调用会建立栈帧,栈帧中对象构造和析构爷要符合后进先出
st1先构造,st2后构造
st2先析构,st1后析构
③拷贝构造函数
概念:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类的对象创建新对象时由编译器自动调用
#include<iostream>
#include<string>
using namespace std;
class student
{
public:
student(string name1 = "