分站式二手车网站源码,外贸网站seo招聘,四川省建设行业数据共享平台官网,专门做游戏的网站目录 2. 类的六个默认成员函数2.1 构造函数2.1.1 构造函数的定义方式 2.2 析构函数2.2.1 析构函数定义方式 2.3拷贝构造函数2.3.1 拷贝构造函数的定义方式2.3.2 深拷贝与浅拷贝 2.4 赋值运算符的重载2.4.1 运算符重载2.4.2 运算符的重载的定义方式2.4.3 默认成员函数#xff1… 目录 2. 类的六个默认成员函数2.1 构造函数2.1.1 构造函数的定义方式 2.2 析构函数2.2.1 析构函数定义方式 2.3拷贝构造函数2.3.1 拷贝构造函数的定义方式2.3.2 深拷贝与浅拷贝 2.4 赋值运算符的重载2.4.1 运算符重载2.4.2 运算符的重载的定义方式2.4.3 默认成员函数赋值运算符重载2.4.4 前置后置的运算符重载 2.5 类与对象穿插巩固练习日期类的实现2.6 const成员函数2.7 默认成员函数取地址操作符重载与const取地址 2. 类的六个默认成员函数 默认成员函数 1 成员函数即所属与定义类的函数只针对所属类只有所属类可以调用的函数而默认成员函数即为定义类时类会默认生成自带的函数。 2 既然会默认生成那么一定的这些函数一定非常重要并且不可或缺究竟什么样的函数会让类定义时要默认生成呢我们接下来进行学习 2.1 构造函数 在C语言的学习中我们定义过各种各样的结构体这些结构体声明出来只是单纯开辟了对应的空间而空间里的值是随机的因此对新创建结构体变量的初始化是必不可少的会影响到后续操作。对于C中的类也是如此因此对实体化对象的初始化必不可少且十分重要而我们自主编写时会经常忘记定义或者调用所以在C中就添加了此函数的默认生成自动调用的内容。 2.1.1 构造函数的定义方式 构造函数在整个对象的声明周期中会自动调用且调用一次构造函数只负责初始化不会开辟空间构造函数的形式 1 函数名与类名相同 2 无返回值 3 实例化对象会自动调用相应的构造函数 4 构造函数可以重载 默认生成的构造函数 内置类型
class Date
{
public:int _year;int _month;int _day;void Print(){cout _year _month _day endl;}
};Date d1;
d1.Print();自定义类型
class stack
{
public:int _capacity;int _top;stack(int capacity 0, int top 0){cout stack() endl;_capacity capacity;_top top;}
};class queue
{
public:stack push_st;stack pop_st;
};queue q1;虽然编译器会帮助我们生成构造函数可是默认生成的构造函数并不让人满意 1 默认生成的构造函数对内置类型会赋予随机值 2 对自定义类型会去调用它们的默认构造函数所以在日常中我们还是应该去自己给类定义需要适合的构造函数 构造函数的定义方式 [类名](传递形参)
{//函数操作
}class Date
{
private:int _year;int _month;int _day;Date(int year 0, int month 0, int day 0){_year year;_month month;_day day;}
};带参数构造函数的传参方式在实例化对象是直接进行传参同时也支持缺省参数 Date d1(2024, 3, 8);
Date d2(2024);C11中为默认构造函数对成员变量初始化为随机值的这一操作做了补丁优化 我们在定义类的成员变量时可以在定义处赋予变量初始默认值这样在我们没有定义构造函数时自定义类型的成员变量也会有合法的初始值 class Date
{
private:int _year 2024;int _month 1;int _day 1;
};默认构造函数不止仅仅是只我们未定义编译器默认生成的函数 1 未定义编译器默认生成的构造函数 2 没有参数的构造函数 3 参数为全缺省参数的构造函数 以上三者统称为默认构造函数 2.2 析构函数 存在资源申请就一定会存在资源的返还我们已经知晓了如何创建一个对象那么我们如何销毁它呢。正常情况下创建的变量会在自己的声明周期结束自动销毁可是我们动态开辟的空间这类资源只要程序不结束我们不去主动销毁那么它就会一直存在当一段程序需要不停的运行时这一点就是致命的,因此析构函数对实例化对象资源的管理就尤为重要。 2.2.1 析构函数定义方式 默认生成的析构函数不会进行资源的深度清理指针所指向动态开辟的空间,只会进行资源的简单清理 class A
{
private:int* _a;int _b;A(){//销毁_b 10;//所指向空间不会被释放_a (int*)malloc(_b * sizeof(int));}
};析构函数的特征及其定义方式 1 函数名由~ 类名构成 2 没有参数没有返回值 3 一个类只存在一个析构函数不存在重载 4 析构函数会在实例化对象生命周期结束时自动调用 ~[类名]()
{//操作
}class B
{
privare:int* _a;;B(){_a (int*)malloc(sizeof(int));}~B(){cout ~B() endl;free(_a)}
};自定义类型的成员变量默认析构函数会去调用它自己的析构函数 拓展练习 2.3拷贝构造函数 使用另一个已经存在的实例化对象将其作为模板创建一个与之一样的新对象 2.3.1 拷贝构造函数的定义方式 拷贝构造函数的特征 1 拷贝构造函数为构造函数的函数重载 2 拷贝构造函数只有一个参数参数类型为所处类的类型引用 补充拷贝构造函数参数类型必须为引用类型的原因产生无穷递归 //err
Date (const Date d)
{}2.3.2 深拷贝与浅拷贝 拷贝构造也为类的默认成员函数之一当我们不去自己定义时编译器自主生成一个拷贝构造函数可是此拷贝构造只会进行值拷贝不会对动态申请得进行拷贝。 我们将值拷贝称为浅拷贝将对原变量的深度资源也进行拷贝的操作称为深拷贝。当自定义类中没有需要深度拷贝的资源时我们也可以省略拷贝构造的定义让编译器自动生成。拷贝构造函数使用场景 1 用已存在的对象创建一个一样的新对象 2 函数参数为类生成临时变量 3 函数返回值为类生成临时变量 Date d1(2024, 3, 9);
//场景1
Date d2(d1);void Print(Date d)
{cout d._year endl;
}
//场景2
Print(d2);//场景3
Date f()
{Date d3(2024);return d3;
}上述场景为生成临时变量而调用拷贝构造在一些时候可以使用引用传参不改变值引用返回原对象不被销毁来规避这一额外开销。 2.4 赋值运算符的重载
2.4.1 运算符重载 我们知道编程语言也是一门语言是用来描述问题与计算机沟通的语言。C中我们引入了类与对象的概念让计算机可以更好更贴切的描述我们所处的世界。 1 对象是更加复杂贴近于现实的变量C中的内置类型变量有着自己运算操作符于运算规则 2可是内置类型的运算符不能使用于更复杂的类上这就导致当对进行这类复杂对象间的计算无法进行由此C引入了运算符重载的概念。 运算符重载的本质是函数这类函数以类似于运算符的函数调用方式来达到近似运算符的操作。 2.4.2 运算符的重载的定义方式
[函数返回值] operator[操作符](函数参数)
{//.......
}运算符重载的注意事项 1 不能通过运算符重载来创建原本不存在的运算符如operator 2 不能通过运算符重载来更改原本内置类型操作符的含义 3 操作符.*::sizeof: ?.这五个操作符不能重载 2.4.3 默认成员函数赋值运算符重载 赋值运算符拥有两个操作数会返回被赋值后的变量赋值运算符的优化 1 传参时因为不会改变参数原本的值所以可以直接传引用const 类 2 因为被赋值的对象不会被销毁所以可以返回引用返回自身支持连续赋值 3 赋值时应进行检测不能让对象自己给自己赋值 class A
{
public:int _a;int _b;A(int a 0, int b 0){_a a;_b b;}A operator(const A x){if(x ! *this){_a x._a;_b x._b;}return *this;}
};注重载的赋值运算符只能作为类的成员函数不能作为全局函数缺少this指针 因为是默认成员函数当我们没有定义时编译器会自行生成但与拷贝构造相似默认生成的赋值运算符重载进行的也是浅拷贝可能会导致资源的丢失。 2.4.4 前置后置的运算符重载 我们已经初步学习了运算符的重载现在我们来学习一下运算符重载中比较特殊的两个运算符前置与后置每当需要对一个运算符进行重载时我们在思考实现逻辑之前首先应该确定的是运算符有几个操作数是否有返回值。当我们以这样的视角去观察前置与后置这一对操作符时我们发现它们重载时它们参数是相同无法进行区分C语言在出现了逻辑漏洞无法形成逻辑的闭环。其实上述无法逻辑闭环的逻辑漏洞在语言的设计上时有出现这种情况下一律都会采取特殊化处理这里的两个运算符同样如此。 前置操作符的重载方式 [返回值] operator()
{//......
}后置操作符的重载方式 [返回值] operator(int)
{//......
}2.5 类与对象穿插巩固练习日期类的实现 实现目标 构造拷贝构造析构函数赋值运算符-前置后置等运算符的重载 Date.h
class Date
{
private:int _year;int _month;int _day;
public:int GetMonthDay(int year, int month){int MonthDay[13] { 0,31,28,31,30,31,30,31,31,30,31,30,31 };int day MonthDay[month];if ((year % 4 0 year % 100 ! 0) || year % 400 0){if (month 2){day;}}return day;}void Print(){cout _year - _month - _day endl;}Date(int year 2024, int month 1, int day 1);//缺省参数在声明处定义Date(const Date d);~Date();Date operator(const Date d);Date operator(int day);int operator-(const Date d);Date operator-(int day);Date operator(int day);Date operator-(int day);bool operator(const Date d);bool operator(const Date d);bool operator(const Date d);bool operator(const Date d);bool operator(const Date d);bool operator!(const Date d);//前置Date operator();//后置Date operator(int);Date operator--();Date operator--(int);
};Date.cpp 默认成员函数 Date::Date(int year, int month, int day)
{//检查日期合法assert(year 1);assert(month 1 month 12);assert(GetMonthDay(year, month) day day 1);_year year;_month month;_day day;
}Date::Date(const Date d)
{_year d._year;_month d._month;_day d._day;
}Date::~Date()
{}Date Date::operator(const Date d)
{if (d ! this){_year d._year;_month d._month;_day d._day;}return *this;
}其他运算符重载 补充运算重载的复用顺序 1先后创建拷贝对象拷贝构造1次 返回临时变量拷贝构造1次 赋值给this指针拷贝1次 返回this指针 2 先后创建拷贝对象拷贝构造1次返回临时变量拷贝构造1次 //2.
Date Date::operator(int day)
{//1. 先加后合法化//2. 累加法_day day;int month_day GetMonthDay(_year, _month);while (_day month_day){_day - month_day;_month;if (_month 12){_year;_month 1;}month_day GetMonthDay(_year, _month);}return *this;
}Date Date::operator(int day)
{Date d(*this);return *this day;
}//先实现-
Date Date::operator-(int day)
{_day - day;while (_day 1){_month--;if (_month 1){_year--;_month 12;}int month_day GetMonthDay(_year, _month);_day month_day;}return *this;
}Date Date::operator-(int day)
{Date d(*this);return d - day;
}//差值法
//int Date::operator-(const Date d)
//{
// //确定先后前 - 后
// Date max(*this);
// Date min(d);
//
// if (max._year min._year)
// {
// max d;
// min *this;
// }
//
// //计算到1月1日的差值
// int max_day 0;
// for (int i 1; i max._month; i)
// {
// max_day GetMonthDay(max._year, i);
// }
// max_day max._day - 1;
//
// int min_day 0;
// for (int i 1; i min._month; i)
// {
// min_day GetMonthDay(min._year, i);
// }
// min_day min._day - 1;
//
// //两年1月1日之间的差值
// int year_day 0;
// while (min._year max._year)
// {
// year_day 365;
// if ((min._year % 4 0 min._year % 100 ! 0) || min._year % 400 0)
// {
// year_day;
// }
// min._year;
// }
//
// return year_day - min_day max_day;
//}//累计法
int Date::operator-(const Date d)
{Date max(*this);Date min(d);if (max._year min._year){max d;min *this;}int day 0;while (max ! min){min;day;}return day;
}-操作符重载差值法思路图解 逻辑比较运算符 bool Date::operator(const Date d)
{if (_year d._year _month d._month _day d._day){return true;}return false;
}bool Date::operator(const Date d)
{if (_year d._year){return true;}else if (_year d._year _month d._month){return true;}else if (_year d._year _month d._month _day d._day){return true;}return false;
}bool Date::operator(const Date d)
{return !(*this d) !(*this d);
}bool Date::operator(const Date d)
{return *this d || *this d;
}bool Date::operator(const Date d)
{return *this d || *this d;
}bool Date::operator!(const Date d)
{return !(*this d);
}//前置
Date Date::operator()
{return *this 1;
}
//后置
Date Date::operator(int)
{Date tmp(*this);*this 1;return tmp;
}Date Date::operator--()
{return *this - 1;
}Date Date::operator--(int)
{Date tmp(*this);*this - 1;return tmp;
}2.6 const成员函数 被this指针被修饰const修饰的成员函数即被称为const成员函数const Date* const this被const修饰的this指针其指向的内容不能被改变。因为this指针为隐藏参数我们无法直接对其进行修饰C中采用了后缀修饰的方式具体如下 Date::Print() const
{count _year - _month - _day endl;
}函数传参时的权限缩可以缩小但不能扩大所以 1 const对象不可以调用非const成员函数权限扩大const Date* const this Date* const this 2 非const对象可以调用const成员函数权限缩小Date* const this const Date* const this 3 const成员函数内不可以调用其它的非const成员函数权限扩大 4 非const成员函数内可以调用其它的const成员函数权限缩小 2.7 默认成员函数取地址操作符重载与const取地址 这两个默认成员函数一般不用我们自己定义编译器默认生成的已经满足绝大部分情况。当想要别人获得额外的一些信息时才会选择重载 Date* operator()
{return this;
}const Date* operator() const
{return this;
}