文章目录
- 1. 构造函数
- 2. 析构函数
- 3. 拷贝构造函数
- 4. 赋值运算符重载
- 5. const成员函数
- 6. 取地址及const取地址操作符重载
前言
C++支持一个类即使是空类,它也会自动生成六个默认的函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
一、构造函数
1.什么是构造函数
构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证 每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
2.构造函数特点
是用来初始化类内置数据类型或者自定义数据类型,函数名和类名相同,没有返回值,它可以重载,由编译器自动调用。至于为什么,它是c++语法规定的,和C语言函数不同。
3,构造函数的类型
1.默认构造函数。
全缺省构造函数和无参的构造函数我们都可以认为是默认构造函数。
(1)如果我们构造函数没写,编译器会自己生成该类的自己的默认构造函数,它不会对内置类型进行初始化,对自定义类型初始化会调用自定义类型自己的构造函数。注意:如果已经写了构造函数,编译器就不会生成自己的默认构造了。
既然它什么都不做,C++给它打了个补丁,允许它在类声明的变量进行赋值,这里的赋值是缺省值,是给初始化列表的。
(2)我们自己写的默认构造函数(全缺省构造函数)还有我们写的无参的构造函数
注意:默认构造函数只能存在一个,因为编译器会不知道调用哪个。
2.有参构造函数。
我们用类创造一个类对象时需要传参。
构造函数的作用例子,我们用栈实现队列
class Stack {//自定义类型
public:
Stack(int b=3)
{
int* temp = (int*)malloc(sizeof(int) * b);
if (temp == nullptr)
{
perror("malloc:");
exit(-1);
}
a= temp;
top= 0;
capacity = b;
}
private:
int capacity;
int* a;
int top;
};
//对于内置类型调用默认构造函数,对于自定义类型调用它的构造函数
class MyQueue {
Stack push;//自定义类型,调用类Stack的构造函数
Stack top;
int _size;//内置类型,调用MyQueue类的默认构造函数
};
总结而言,就是一个类中内置类型调用它自己的构造函数,对于自定义类型调用那个类型自己的构造函数 ,当一个类中既有自定义类型又有内置类型时而且没有写构造函数时,有些编译器(VS)会优化也会对内置类型进行初始化,然而并不是所有编译器都会优化,我们当对这样的内置类型当成不处理。这里的_sizeC++语法上来编译器自己生成的默认构造函数是不会初始化它的。
二、析构函数
1.什么是析构函数
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
2.特点
1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
注意:析构 函数不能重载
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数
3.析构函数的调用过程(可通过调试)
如果有一个 MyStack类对象,main函数在结束的时候会调用MyQueue的析构函数,而myStack push和myStack top它的析构函数是通过mian调用MyQueue的析构函数间接调用的,我们可以通过调试可以查看调用过程。
4.总结
对于一个类的内置类型,调用默认的析构函数,自定义类型调用它的析构函数
其实对于内置类型,我们可以不写析构函数直接用默认生成的析构函数,它会处理回收内置类型变量。然而对于栈这样的类需要而外开辟空间的,我们必须写它的析构函数,不然会造成内存泄漏。
(如果我们不写stack的析构函数,那编译器调用它的时默认的析构函数,只是把int*a开变量空间给回收,但是另外malloc()开辟的空间还是存在的,这就会造成内存泄漏)。
三, 拷贝构造函数
1.拷贝构造函数用处
那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢?
Date d1;//对象d1
Date d2(d1);
Date d3=d1;
拷贝构造函数就是将一个对象变成两个,它们都是一样的,就像双胞胎兄弟。
2.特点
拷贝构造函数是构造函数的重载,它的函数形参是引用&。它是单个形参,另一个形参在用已存 在的类类型对象创建新对象时由编译器自动调用(隐藏的this指针)。如果我们写了复制构造函数,传的值不是引用就会发生无限递归问题,因为调用这个函数参数先要拷贝一份对象,要拷贝对象就要调用拷贝构造..........
3.对于默认生成拷贝构造函数完成的是值拷贝又叫浅拷贝,有点像C语言函数传参数传的是传结构体,形参是实参的拷贝按照字节序拷贝。
3.拷贝构造函数主要用途
拷贝构造函数主要处理的是一个类中有另外开辟一段连续空间,用默认生成的拷贝构造它是值拷贝,两个对象的*a都指向同一块空间,程序结束时会各自调用析构函数,连续释放了同一块空间这是错误的
这里我们没有写拷贝构造,调用的是编译器自己生成的拷贝构造是值拷贝,2个对象调用了两次析构函数,释放了同一个空间两次。
我们可以用拷贝构造函数解决这个问题
四.赋值运算符重载
关键字:operator+重载的运算符符号
1.重载的规则
(1)必须有一个类的参数
(2)不是所有符号都可以重载 .* :: sizeof ?: . 注意以上5个运算符不能重载。
注意:*是可以重载的,因为*既可以代表运算符也可以指针的解引用。
(3)不能改变操作符,比如operator@,编译器识别不了。
(4)用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
在c语言中,我们学到的内置类型它们用到的操作符+ - *等,如果我们要操作自定义类型,就需要对运算符重载。
2.重载<<和>>
class Date {
public:
Date(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
void print()const//权限平移const Date* const this
{
cout << _year << "/" << _month << "/" << _day;
}
/*ostream& operator<<(ostream& out)//不要把<<的重载变成成员函数
{
out << _year << "年" << _month << "月" << _day << "日" << endl;
return out;
}*/
friend ostream& operator<<(ostream& out, const Date& d);//声明为有友元,可访问私有
friend istream& operator>>(istream& in, Date& d);
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out,const Date& d)
{
out <<d. _year << "年" <<d. _month << "月" <<d. _day << "日" << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
ostream是输出流对象,istream是输入流对象。operator<<和opeartor>>我们把这两个定义为全局函数,并且在类中把它们声明为这个类的友元,就可以访问私有成员,如果把它定义在类里面,它就变成成员函数了,成员函数虽然通过隐藏的*this访问私有,如果连续输出还要加括号保证优先级问题和返回值
五. const成员函数
用const修饰类中的成员函数,实际是修饰那个隐藏的this指针。如果不用const修饰,const修饰的对象调用该成员函数就会报错,这里涉及到const权限扩大的问题。
const Date d1(2020,2,2)------->指针类型为const Date*
Date* this--------->类型为Date*
const Date*-------->Date*权限放大,这是错误的,权限可以平移和缩小,不可以放大。
1.成员函数的定义原则
const成员函数,可以保护对象不被修改,增加了安全性。
1.能被定义成const成员函数的函数最好加上const,这样const对象和非const对象都可以调用const成员函数
2.要修改成员变量的函数不加const
这两个默认成员函数一般不用重新定义 ,编译器默认会生成。它们构成重载。
class Date
{
public :
Date* operator&()
{
return this ;
}
const Date* operator&()const
{
return this ;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
};
注意:如果写了其中一个重载,编译器就不会生成默认成员函数,非const对象和const对象取地址都会调用写的那个函数,如果没写或者写了两个就会各自匹配各自类型的那个函数(const和非const).