个人主页
创作不易,感谢大家的关注!
⭐一、类的默认成员函数
定义:所谓的默认成员函数,就是用户没有显式实现,而编译器会自动生成的成员函数就被称为默认成员函数。
在一个类中,在我们不写的情况下编译器会自动生成以下六个默认成员函数。其中最重要的是前四个,而取地址重载可以作为了解即可。
💎二、构造函数
-
定义:构造函数是一个特殊的成员函数,其名字与类名相同,在创建类类型对象时由编译器自动调用,保证每一个对象成员都有初始值,并在对象的生命周期内只调用一次。
-
特点:
1.函数名与类名相同。
2.没有返回值。
3.对象实例化时系统会自动调用对应的构造函数。
4.构造函数可以重载。 -
功能:
构造函数不是用来构造对象的,它是来完成对象初始化的。 -
注意事项:
1.如果类中没有显式定义构造函数,那么C++编译器会自动生成一个无参的默认构造函数,一旦用户定义则编译器将不再生成。
2.无参构造函数、全缺省构造函数和当我们不写构造时编译器默认生成的构造函数,都被称为默认构造函
数。但是这三个函数有且仅有一个存在,不能同时存在。
演示代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
// 1.无参构造函数
Date()
{
_year = 1;
_month = 1;
_day = 1;
}
//2.带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//3.全缺省构造函数
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
⏱️三、析构函数
- 概念:与构造函数的功能相反,析构函数并不是完成对对象本身的销毁,C++规定对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作。
- 特点:
1.析构函数名是在类名前加上字符 ~。
2.无参数和无返回值。
3.⼀个类只能有⼀个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4.对象生命周期结束时,编译器会自动调用析构函数。 - 功能:
完成对象中资源的清理释放工作。 - 注意事项:
1.我们不写编译器自动生成的析构函数对内置类型成员不做处理,自定义类型成员会调用他的析构函数。
2.如果类中没有申请资源时,析构函数可以不写,直接使用编译器自动生成的默认析构函数。
(注:在有资源申请时,一定要自己写析构函数,否则会造成资源泄露)
3.一个局部域的多个对象,C++规定后定义的先析构。
代码演示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Time
{
public:
//析构函数
~Time()
{
cout << "~Time()" << endl;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
public:
private:
int _year;
int _month;
int _day;
// 自定义类型
Time _t;
};
int main()
{
Date a;
return 0;
}
🏝️ 四、拷贝构造函数
- 概念:拷贝构造函数是通过一个对象来初始化另一个对象,也是一个特殊的构造函数。
- 特点:
1.拷贝构造函数是构造函数的⼀个重载。
2.拷贝构造函数的参数只有⼀个且必须是类类型对象的引用,使用传值方式是编译器会产生报错,因为在语法逻辑上会引发无穷递归。
3.C++规定自定义类型对象在进行拷贝行为时必须调用拷贝构造。 - 注意事项:
若未显式定义拷贝构造时,编译器会自动生成拷贝构造函数。而自动生成的拷贝构造对内置类型成员变量会完成值拷贝或浅拷贝(⼀个字节⼀个字节的拷贝),在对自定义类型成员变量时会调用它本身的拷贝构造。
代码演示:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)// 构造函数
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "年" << _month << "月" << _day << "日" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 7, 20);
//用已存在的对象d1来初始化对象d2
Date d2(d1);
d1.Print();
d2.Print();
return 0;
}
🎄五、赋值运算符重载
-
定义:C++为了增强代码的可读性引入了运算符重载,允许我们通过运算符重载的形式来指定新的含义。
-
特点:
1.运算符重载是具有特殊名字的函数,它的名字是由operator和后面要定义的运算符共同构成,具有其返回类型和参数列表以及函数体。
2.运算符重载以后,其优先级和结合性与对应的内置类型运算符保持⼀致。 -
3.如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算符对象少⼀个。
-
注意事项:
1.不能通过连接语法中没有的符号来创建新的操作符:比如operator@。
2.重载操作符至少有⼀个类类型参数,不能通过运算符重载改变内置类型对象的含义。
3.sizeof 、:: 、.* 、?: 、. 这5个运算符不能重载。
4.重载++运算符时,有前置++和后置++,因此.C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,方便区分。
5.重载<<和>>时,需要重载为全局函数,因为重载为成员函数时,this指针默认抢占了第⼀个形参位置,而第一个形参的位置为左侧运算符对象。而重载为全局函数时就可以把ostream/istream放到第⼀个形参位置。
🏠六、取地址运算符重载
取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,⼀般这两个函数由编译器自动生成的就足够我们使用了,不需要额外去显式实现。
🎉const成员
-
定义:将const修饰的成员函数就称为const成员函数,const修饰成员函数放到成员函数参数列表的后面。
-
功能:const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
-
下面有这么几个问题:
1.const成员能够调用非const成员的函数吗?
2.非const成员可以调用const成员函数吗?
3.const成员函数内可以调用其他的非const成员函数吗?
4.非cosnt成员函数内可以调用其他的cosnt成员函数吗?
我们先来揭晓答案:
1.不可以 2.可以 3.不可以 4.可以
下面对上述问题进行阐释:
1.非const成员函数,即成员函数的this指针没有被const所修饰,当我们传入一个const修饰的对象时,被一个非const修饰的成员函数所接受,属于权限放大,因此函数调用失败。
2.const成员函数,即成员函数的this指针被const所修饰,当我们传入一个非const修饰的对象时,被一个const修饰的成员函数所接受,属于权限缩小,函数调用成功。
3…在一个被const所修饰的成员函数中调用其他没有被const所修饰的成员函数,属于权限的放大,因此函数调用失败。
4.在一个没有被const所修饰的成员函数中调用其他被const所修饰的成员函数,属于权限缩小,函数调用成功。
总结:权限可以被放大,但不能被缩小,否则就会出现报错。