青岛网站设计公司排名,网站开发培训流程,营销型建设,wordpress 照片墙好的继上期#xff0c;我们今天带来c类与对象系列的继续学习。 类的6个默认成员函数 如果一个类中什么成员都没有#xff0c;简称为空类。 空类中真的什么都没有吗#xff1f;并不是#xff0c;任何类在什么都不写时#xff0c;编译器会自动生成以下6个默认成员 函数。 …好的继上期我们今天带来c类与对象系列的继续学习。 类的6个默认成员函数 如果一个类中什么成员都没有简称为空类。 空类中真的什么都没有吗并不是任何类在什么都不写时编译器会自动生成以下6个默认成员 函数。 默认成员函数用户没有显式实现编译器会生成的成员函数称为默认成员函数。 六个默认成员函数会实现6个功能我们先来看第一个
构造函数
上一段代码
#define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public:void Init(int year, int month, int day){_year year;_month month;_day day;}void Printf(){cout _year / _month / _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();return 0;
}大家在刚开始写代码的时候比如说这里写了一个date类我们忘记了初始化直接调用printf函数由于没有初始化三个变量的值就会使三个随机数 这是不是就麻烦了这个事情不仅仅是我们经常忘记c祖师爷也经常忘记所以祖师爷就想给c多个功能自己初始化所以祖师爷就搞了一个新的东西构造函数 构造函数的特性 构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任 务并不是开空间创建对象而是初始化对象。 其特征如下 1. 函数名与类名相同。 2. 无返回值。 不需要写void 3. 对象实例化时编译器自动调用对应的构造函数。 4. 构造函数可以重载。 可以有多个构造函数多种初始化方式 我们给上边日期类写一个构造函数试试看看是否真的可以初始化 #define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public://构造函数Date(){_year 2023;_month 8;_day 30;cout 构造函数 endl;}void Printf(){cout _year / _month / _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();return 0;
}很好我们可以发现该类就是调用了我们写构造函数进行了初始化日期并且我们无需调用省下了很多时间 现在的初始化没有传参是规定好的就是我们构建无数次日期类的变量都是这个时间如果我们想自己在外部主函数自己传一个日期进行初始化该怎么办 非常简单再写一个带参的构造函数就可以了 上代码 #define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public://构造函数Date(){_year 2023;_month 8;_day 30;cout 构造函数 endl;}//有参构造函数Date(int year,int month,int day){_year year;_month month;_day day;cout 有参构造函数 endl;}void Printf(){cout _year / _month / _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023,1,1);d2.Printf();return 0;
}可以看到我们另外又写了一个构造函数是有参数的构造函数两个构造函数构成函数重载如果我们没传参就自动调用第一个无参构造函数如果又传参就按照我们自己的想法调用第二个有参构造函数进行初始化是不是和我们前两期函数重载的知识点结合起来了另外大家要注意一下d2的传参数方式很新很方便比调用init要方便的多这个大家记住就行了。 运行截图论证 再回想一下我们第二期讲的内容是不是有一个缺省参数好好好那么是不是可以根据这个知识点把两个构造参数合二为一 #define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public:Date(int year2023,int month8,int day30){_year year;_month month;_day day;cout 有参构造函数 endl;}void Printf(){cout _year / _month / _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023,1,1);d2.Printf();return 0;
}这样不单单就简介了还更灵活了看不懂的同学自觉去看前两期内容 两次都是调用的这个构造函数这就是缺省的魅力 是不是还可以这么玩 #define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public:Date(int year2023,int month8,int day30){_year year;_month month;_day day;cout 有参构造函数 endl;}void Printf(){cout _year / _month / _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023,1,1);d2.Printf();Date d3(2023);d3.Printf();Date d4(2023, 12);d4.Printf();return 0;
}好好好缺省参数被我们玩坏了 刚刚我们看的是日期类的构造函数相对来说比较简单现在我们来进阶一下看看栈的构造函数 class Stack { public: Stack() { a nullptr; top capacity 0; } void Push(int x) { if (top capacity) { cout capacity 扩容 endl; size_t newcapacity capacity 0 ? 4:capacity * 2; a (int*)realloc(a, sizeof(int) * newcapacity); capacity newcapacity; } a[top] x; } private: int *a; int top; int capacity; int size; }; 众所周知构造函数也叫默认成员函数默认什么意思也就是说我们不去写构造函数编译器也会自动生成 构造函数也是默认成员函数我们不写编译器会自动生成编译生成的默认构造的特点: 1、我们不写才会生成我们写了就不会生成了 2、内置类型的成员不会处理 3、自定义类型的成员才会处理会去调用这个成员的构造函数 像是我们之前写的那个日期类如果我们没写构造函数他也不会自动生成因为三个成员都是内置类型 一般情况下都需要我们自己写构造函数如果类变量都是自定义变量可以有选择不写 析构函数
通过前面构造函数的学习我们知道一个对象是怎么来的那一个对象又是怎么没呢的 析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作。 析构函数的特性
析构函数是特殊的成员函数其特征如下
1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数。注意析构 函数不能重载
4. 对象生命周期结束时C编译系统系统自动调用析构函数 上代码 #define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public:Date(int year 2023, int month 8, int day 30){_year year;_month month;_day day;cout 有参构造函数 endl;}void Printf(){cout _year / _month / _day endl;}~Date(){cout 析构函数 endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Printf();Date d2(2023, 1, 1);d2.Printf();return 0;
}看我们写的析构函数自动被调用了 日期类的析构函数我们看不出什么来来试试栈的析构函数 #define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Stack
{
public:Stack(){cout 构造函数 endl;a nullptr;top capacity 0;}void Push(int x){if (top capacity){cout capacity 扩容 endl;size_t newcapacity capacity 0 ? 4 : capacity * 2;a (int*)realloc(a, sizeof(int) * newcapacity);capacity newcapacity;}a[top] x;}~Stack(){cout 析构函数 endl;free(a);a nullptr;top capacity 0;}
private:int* a;int top;int capacity;int size;
};
int main()
{Stack s1;return 0;
}自动调用无论写多少个所以这就生下了我们很多初始化和删除的时间 拷贝构造函数 上代码 #includeiostream
using namespace std
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}// Date(const Date d) // 正确写法Date(const Date d) // 错误写法编译报错会引发无穷递归{_year d._year;_month d._month;_day d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2(d1);return 0;
} 直接拷贝的d1给d2赋值 拷贝构造的特征 拷贝构造函数也是特殊的成员函数其特征如下 1. 拷贝构造函数是构造函数的一个重载形式。 2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器直接报错 因为会引发无穷递归调用。 赋值运算符重载 上代码 #define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public:Date(int year 2023, int month 8, int day 30){_year year;_month month;_day day;cout 有参构造函数 endl;}void Printf(){cout _year / _month / _day endl;}~Date(){cout 析构函数 endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2023, 1, 1);Date d2(2023, 1, 2);d1 d2;return 0;
}大家看看这样比较两个日期类的变量行不行 答案是当然不行 但是这样写 int i,j; ij; 这样比较就可以这是因为编译器知道int变量的存储模式和比较方式 那么我们可不可以让编译器也可以直接比较date 这就涉及到这个课题内容运算符重载 #define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#includeiostream
using namespace std;
class Date
{
public:Date(int year 2023, int month 8, int day 30){_year year;_month month;_day day;cout 有参构造函数 endl;}void Printf(){cout _year / _month / _day endl;}~Date(){cout 析构函数 endl;}//private:int _year;int _month;int _day;
};
bool operator(const Date x1, const Date x2)
{if (x1._year x2._year){return true;}else if (x1._year x2._year x1._month x2._month){return true;}else if (x1._year x2._year x1._month x2._month x1._day x2._day){return true;}else{return false;}
}
int main()
{Date d1(2023, 1, 1);Date d2(2023, 1, 2);cout(d1 d2)endl;return 0;
}有函数重载就有运算符重载上边就是使用规则大家记住就行了 那有运算符就有,,,,,-,,- 博主在这里一一实现了 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;}bool 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;}else{return false;}}bool operator(const Date d){return _year d._year _month d._month _day d._day;}// d1 d2bool operator(const Date d){return *this d || *this d;}bool operator(const Date d){return !(*this d);}bool operator(const Date d){return !(*this d);}bool operator!(const Date d){return !(*this d);}int GetMonthDay(int year, int month){int monthArray[13] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };if (month 2 ((year % 4 0 year % 100 ! 0) || (year % 400 0))){return 29;}return monthArray[month];}Date operator(int day){_day day;while (_day GetMonthDay(_year, _month)){// 月进位_day - GetMonthDay(_year, _month);_month;// 月满了if (_month 13){_year;_month 1;}}return *this;}Date operator(int day){Date tmp(*this);tmp day;return tmp;//tmp._day day;//while (tmp._day GetMonthDay(tmp._year, tmp._month))//{// // 月进位// tmp._day - GetMonthDay(tmp._year, tmp._month);// _month;// // 月满了// if (tmp._month 13)// {// tmp._year;// tmp._month 1;// }//}//return tmp;}private:// 内置类型int _year;int _month;int _day;
}; 关于日期各种加减乘除运算的逻辑实现是没有任何难度的就是年完月月完日进位加 大家要理解的是重载的操作 注意 不能通过连接其他符号来创建新的操作符比如operator 重载操作符必须有一个类类型参数 用于内置类型的运算符其含义不能改变例如内置的整型不 能改变其含义 作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐 藏的this .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出 现。 好的类和对象的中篇就到这里对于默认成岩函数基本就接好玩了期待三连