网站建设动画教程,企业信息化管理软件有哪些,杭州网站建设公司有哪些,如何确定wordpress#x1f9d1;#x1f4bb;作者#xff1a; 情话0.0 #x1f4dd;专栏#xff1a;《C从入门到放弃》 #x1f466;个人简介#xff1a;一名双非编程菜鸟#xff0c;在这里分享自己的编程学习笔记#xff0c;欢迎大家的指正与点赞#xff0c;谢谢#xff01; 类和对… 作者 情话0.0 专栏《C从入门到放弃》 个人简介一名双非编程菜鸟在这里分享自己的编程学习笔记欢迎大家的指正与点赞谢谢 类和对象中前言一、构造函数1. 构造函数的概念2. 构造函数的特性二、析构函数1. 析构函数的概念2. 析构函数的特征三、 拷贝构造函数1. 拷贝构造函数的概念2. 拷贝构造函数的特征四、 赋值运算符重载1.运算符重载2. 赋值运算符重载四、const成员函数五、取地址及const取地址操作符重载总结前言 在上一篇文章中提到过空类的存在它的大小为一个字节目的就是为了标识这个类的存在。但是空类中真的什么都没有吗当然不是的任何类在什么都不写时编译器会自动生成以下六个默认成员函数。而这六个默认成员函数只会在用户没有显式定义的情况下被编译器自动生成如若用户自己显示定义了这几个函数那么编译器不会自动生成默认的成员函数。编译器自动生成的函数称为默认成员函数。 一、构造函数
1. 构造函数的概念
class Date
{
public:void Init(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day;
};int main()
{Date d;d.Init(2000, 1, 9);d.Print();return 0;
}在创建了一个类对象可以通过公有方法 Init 给对象设置日期但如果每次创建对象时都调用该方法设置信息那是不是有点麻烦那能否在对象创建时就将信息设置进去呢 构造函数是一个特殊的成员函数名字与类名相同创建类类型对象时由编译器自动调用保证每个数据成员都有 一个合适的初始值并且在对象的生命周期内只调用一次。
2. 构造函数的特性 构造函数是特殊的成员函数构造函数的虽然名称叫构造但是需要注意的是构造函数的主要任务并不是开空间创建对象而是初始化对象。
其特征如下
函数名与类名相同。无返回值。对象实例化时编译器自动调用对应的构造函数。构造函数可以重载。
class Date
{
public :// 1.无参构造函数Date (){}// 2.带参构造函数Date (int year, int month, int day){_year year ;_month month ;_day day ;}
private :int _year ;int _month ;int _day ;
};
int main()
{Date d1; // 调用无参构造函数Date d2 (2000, 1, 9); // 调用带参的构造函数
}如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显式定义编译器将不再生成。
class Date
{
public:/*// 如果用户显式定义了构造函数编译器将不再生成Date(int year, int month, int day){_year year;_month month;_day day;} */ void Print(){cout _year - _month - _day endl;}
private:int _year;int _month;int _day;
};
int main()
{ // 将Date类中构造函数屏蔽后代码可以通过编译因为编译器生成了一个无参的默认构造函数// 将Date类中构造函数放开代码编译失败因为一旦显式定义任何构造函数编译器将不再生成// d1对象并没有初始值所以应该去调用无参构造函数或者全缺省构造函数而显示定义的构造函数并非默认构造函数Date d1;return 0;
}无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个。 注意无参构造函数、全缺省构造函数、编译器默认生成的构造函数都是默认成员函数。
class Date
{
public:Date()//无参的构造函数{_year 1900 ;_month 1 ;_day 1;}Date (int year 2000, int month 1, int day 9)//全缺省构造函数{_year year;_month month;_day day;}
private :int _year ;int _month ;int _day ;
};上面的代码会有问题因为同时出现了两个默认构造函数当定义了一个无初始值的对象时编译器就不知道该去调用哪个构造函数。 关于编译器生成的默认成员函数我们会发现不实现构造函数的情况下编译器会生成默认的构造函数。但是看起来默认构造函数又好像没什么用一个对象调用了编译器生成的默认构造函数但是这个对象的年月日依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用其实这也算是C的小缺点吧可能祖师爷在这个点上并没有想那么多。 C把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型如int/char…自定义类型就是我们使用class/struct/union等自己定义的类型看看下面的程序就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数。
class Time
{
public:Time(){cout Time() endl;_hour 0;_minute 0;_second 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};int main()
{Date d;return 0;
}注意C11 中针对内置类型成员不初始化的缺陷又打了补丁即内置类型成员变量在类中声明时可以给默认值。 当你在定义对象时给了初始值那么就会使用你所给的初始值若没给初始值那么就会使用这个在声明时给到的默认值避免随机值的出现。
class Date
{
private:// 基本类型(内置类型)
int _year 2000;
int _month 1;
int _day 9;// 自定义类型
Time _t;
};二、析构函数
1. 析构函数的概念 通过对构造函数的学习明白了一个对象是怎样来的那么一个对象又是怎么没的呢 析构函数与构造函数功能相反析构函数不是完成对象的销毁局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数完成类对象的资源清理工作。
2. 析构函数的特征 析构函数是特殊的成员函数其特征如下
析构函数名是在类名前加上字符 ~。无参数无返回值。一个类有且只有一个析构函数。若未显式定义系统会自动生成默认的析构函数。对象生命周期结束时C编译系统系统自动调用析构函数。编译器生成的默认析构函数对会自定类型成员调用它的析构函数。
class Time
{
public:~Time(){cout ~Time() endl;}
private:int _hour;int _minute;int _second;
};class Date
{
private:// 基本类型(内置类型)int _year 1970;int _month 1;int _day 1;// 自定义类型Time _t;
};int main()
{Date d;return 0;
}程序运行结束后输出~Time() 在main方法中根本没有直接创建Time类的对象为什么最后会调用Time类的析构函数 解释 在main函数中创建了Date类其中包含四个成员变量其中一个为自定义类型变量在创建了Date类对象时不仅通过Date类的构造函数对内置类型的三个变量初始化还要去调用自定义类型变量对应的构造函数完成初始化那么程序退出时首先要完成对Date类对象的析构除此之外还要对Time类完成析构函数因为在Date类中为完成 _t 的初始化而调用了Time类的构造函数。 创建哪个类的对象则调用该类的析构函数销毁那个类的对象则调用该类的析构函数。
三、 拷贝构造函数
1. 拷贝构造函数的概念 拷贝构造函数是通过一个已经创建好的类对象去创建每一个一摸一样的类对象只有单个形参该形参是对本类类型对象的引用(一般常用const修饰)在用已存在的类类型对象创建新对象时由编译器自动调用。
2. 拷贝构造函数的特征 拷贝构造函数也是特殊的成员函数其特征如下
1. 拷贝构造函数是构造函数的一个重载形式。 2. 拷贝构造函数的参数只有一个且必须使用引用传参使用传值方式会引发无穷递归调用。
class Date
{
public:Date(int year 2000, int month 1, int day 9){_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 而采用传值的方式会对 d1 重新创建一个临时对象 d 这个创建临时对象的过程又被认为是一个拷贝构造的过程那么就又会去调用拷贝构造函数以此类推就会出现拷贝构造函数的无穷递归而采用传引用的方式就不会出现创建临时对象这个过程。
3. 若未显示定义系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝这种拷贝我们叫做浅拷贝或者值拷贝。
class Time
{
public:Time(){_hour 1;_minute 1;_second 1;}Time(const Time t){_hour t._hour;_minute t._minute;_second t._second;cout Time::Time(const Time) endl;}
private:int _hour;int _minute;int _second;
};class Date
{
private:// 基本类型(内置类型)int _year 1970;int _month 1;int _day 1;// 自定义类型Time _t;
};
int main()
{ Date d1; // 用已经存在的d1拷贝构造d2此处会调用Date类的拷贝构造函数// 但Date类并没有显式定义拷贝构造函数则编译器会给Date类生成一个默认的拷贝构造函数Date d2(d1);return 0;
}注意在编译器生成的默认拷贝构造函数中内置类型是按照字节方式直接拷贝的而自定义类型是调用其拷贝构造函数完成拷贝的。
4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了还需要自己显式实现吗当然像日期类这样的类是没必要的。那么下面的类呢验证一下试试
// 这里会发现下面的程序会崩溃掉,原因就在于析构函数
typedef int DataType;
class Stack
{
public:Stack(size_t capacity 10){_array (DataType*)malloc(capacity * sizeof(DataType));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}void Push(const DataType data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}private:DataType *_array;size_t _size;size_t _capacity;
};int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);return 0;
}通过调试发现对象 s1 和对象 s2 的其中一个参数array的地址是一样的这也就问题所在。 通过构造函数创建了一个类对象 s1 并为其开辟了十字节的空间然后再为其中存入了4个元素 s2 对象使用 s1 拷贝构造而 Stack 类中没有显式定义拷贝构造函数则编译器会给 Stack 类生成一个默认的拷贝构造函数默认的拷贝构造函数是按值拷贝的即将对象 s1 中的所有内容拷贝给 s2 s1类对象中第一成员变量是一个地址相当于把地址复制给了 s2那么 s1 和 s2 中的 第一个成员变量指向了同一块空间 当程序退出时s1 和 s2 都要销毁s2 先销毁通过析构函数将 _array 数组那块空间释放掉但是对象 s1 并不知道这块空间已经释放当它再次通过析构函数释放空间时就出现程序崩溃。
注意类中如果没有涉及资源堆内存空间、文件指针等管理时拷贝构造函数是否写都可以一旦涉及到资源申请时则拷贝构造函数是一定要写的否则就是浅拷贝。 5. 拷贝构造函数的典型应用场景 使用已存在对象创建新对象 函数参数类型为类类型对象 函数返回值类型为类类型对象 class Date
{
public:Date(int year, int month, int day){cout Date(int,int,int): this endl;} Date(const Date d){cout Date(const Date d): this endl;}~Date(){cout ~Date(): this endl;}private:int _year;int _month;int _day;
};Date Test(Date d)
{Date tmp(d);return tmp;
}int main()
{Date d1(2000,1,9);Test(d1);return 0;
}为了提高程序效率一般在对象传参时尽量使用引用类型返回可根据实际场景选择是否也可以选择引用返回。 四、 赋值运算符重载
1.运算符重载 C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数具有其返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 函数名字为关键字operator后面接需要重载的运算符符号。 函数原型返回值类型 operator 操作符 (参数列表)
注意 ★ 不能通过连接其他符号来创建新的操作符比如operator ★ 重载操作符必须有一个类类型 ★ 用于内置类型的操作符其含义不能改变例如内置的整型不 能改变其含义 ★ 作为类成员的重载函数时其形参看起来比操作数数目少1因为成员函数中有一个默认的形参this限定为第一个形参 ★ .* 、:: 、sizeof 、?: 、. 注意以上5个运算符不能重载。 class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month; _day day;}// bool operator(Date* this, const Date d2)// 这里需要注意的是左操作数是this指向的调用函数的对象bool operator(const Date d2){return _year d2._year; _month d2._month _day d2._day;}
private:int _year;int _month;int _day;
};
int main ()
{Date d1(2023, 1, 9);Date d2(2000, 1, 9);cout(d1 d2)endl; return 0;
}2. 赋值运算符重载
1. 赋值运算符重载格式 参数类型const T传递引用可以提高传参效率 返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值 检测是否自己给自己赋值 返回*this 要复合连续赋值的含义 class Date
{
public :Date(int year 2000, int month 1, int day 9){_year year;_month month;_day day;} Date (const Date d){_year d._year;_month d._month;_day d._day;}Date operator(const Date d){if(this ! d){_year d._year;_month d._month;_day d._day;}return *this;}
private:int _year ;int _month ;int _day ;
};2. 赋值运算符只能重载成类的成员函数不能重载成全局函数
class Date
{
public:Date(int year 1900, int month 1, int day 1){ _year year;_month month;_day day;}int _year;int _month;int _day;
};// 赋值运算符重载成全局函数注意重载成全局函数时没有this指针了需要给两个参数
Date operator(Date left, const Date right)
{if (left ! right){left._year right._year;left._month right._month;left._day right._day;}return left;
}// 编译失败
// error C2801: “operator ”必须是非静态成员原因 赋值运算符如果不显式实现编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突了故赋值运算符重载只能是类的成员函数。
3. 用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝浅拷贝。注意内置类型成员变量是直接赋值的而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
class Time
{
public:Time(){_hour 1;_minute 1;_second 1;}Time operator(const Time t){if (this ! t){_hour t._hour;_minute t._minute;_second t._second;}return *this;}private:int _hour;int _minute;int _second;
};class Date
{
private:// 基本类型(内置类型)int _year 2000;int _month 1;int _day 1;// 自定义类型Time _t;
};int main()
{Date d1;Date d2;d1 d2;return 0;
}既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了还需要自己实现吗如果类中未涉及到资源管理赋值运算符是否实现都可以一旦涉及到资源管理则必须要实现。这就和拷贝构造是一个道理。
四、const成员函数 将const修饰的“成员函数”称之为const成员函数const修饰类成员函数实际修饰该成员函数隐含的this指针表明在该成员函数中不能对类的任何成员进行修改。 class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}void Display(){cout Display() endl;cout year: _year endl;cout month: _month endl;cout day: _day endl endl;}void Display() const{cout Display()const endl;cout year: _year endl;cout month: _month endl;cout day: _day endl endl;}
private:int _year; // 年int _month; // 月int _day; // 日};int main()
{Date d1(2023, 3, 1);d1.Display();const Date d2(2023, 3, 1);d2.Display();return 0;
}注意const 修饰成员函数有两种 当const 处在成员函数的最前面时它代表的意思是该函数的返回值不可被修改当const 处在成员函数的最末尾时它代表的意思是该函数的成员变量不可被修改。 五、取地址及const取地址操作符重载
class Date
{
public :Date* operator(){return this ;}const Date* operator()const{return this ;}
private :int _year ; int _month ; int _day ;
};这两个运算符一般不需要重载使用编译器生成的默认取地址的重载即可只有在特殊的情况下才需要重载比如你想让获取到指定的内容 总结
以上就是对类的六大默认成员函数的简单介绍掌握了这些知识对后面的C学习会有很大的步骤我也相信自己会一步一步往前走更上一层楼 文章转载自: http://www.morning.zzgtdz.cn.gov.cn.zzgtdz.cn http://www.morning.ckhry.cn.gov.cn.ckhry.cn http://www.morning.zpfr.cn.gov.cn.zpfr.cn http://www.morning.rzjfn.cn.gov.cn.rzjfn.cn http://www.morning.fsqbx.cn.gov.cn.fsqbx.cn http://www.morning.pwsnr.cn.gov.cn.pwsnr.cn http://www.morning.fksxs.cn.gov.cn.fksxs.cn http://www.morning.mfzyn.cn.gov.cn.mfzyn.cn http://www.morning.pslzp.cn.gov.cn.pslzp.cn http://www.morning.xmnlc.cn.gov.cn.xmnlc.cn http://www.morning.fypgl.cn.gov.cn.fypgl.cn http://www.morning.yqqgp.cn.gov.cn.yqqgp.cn http://www.morning.wkknm.cn.gov.cn.wkknm.cn http://www.morning.rkjz.cn.gov.cn.rkjz.cn http://www.morning.xqndf.cn.gov.cn.xqndf.cn http://www.morning.dmkhd.cn.gov.cn.dmkhd.cn http://www.morning.mhpmw.cn.gov.cn.mhpmw.cn http://www.morning.brbmf.cn.gov.cn.brbmf.cn http://www.morning.mrgby.cn.gov.cn.mrgby.cn http://www.morning.mrccd.cn.gov.cn.mrccd.cn http://www.morning.clbzy.cn.gov.cn.clbzy.cn http://www.morning.ccffs.cn.gov.cn.ccffs.cn http://www.morning.pflpb.cn.gov.cn.pflpb.cn http://www.morning.dmzfz.cn.gov.cn.dmzfz.cn http://www.morning.gwsfq.cn.gov.cn.gwsfq.cn http://www.morning.yrmgh.cn.gov.cn.yrmgh.cn http://www.morning.bynf.cn.gov.cn.bynf.cn http://www.morning.zxhpx.cn.gov.cn.zxhpx.cn http://www.morning.mxdhy.cn.gov.cn.mxdhy.cn http://www.morning.whclz.cn.gov.cn.whclz.cn http://www.morning.xdfkrd.cn.gov.cn.xdfkrd.cn http://www.morning.kjnfs.cn.gov.cn.kjnfs.cn http://www.morning.zcqbx.cn.gov.cn.zcqbx.cn http://www.morning.rxhsm.cn.gov.cn.rxhsm.cn http://www.morning.dljujia.com.gov.cn.dljujia.com http://www.morning.qfmns.cn.gov.cn.qfmns.cn http://www.morning.qhvah.cn.gov.cn.qhvah.cn http://www.morning.qsszq.cn.gov.cn.qsszq.cn http://www.morning.zlnyk.cn.gov.cn.zlnyk.cn http://www.morning.hrydl.cn.gov.cn.hrydl.cn http://www.morning.pflpb.cn.gov.cn.pflpb.cn http://www.morning.xqzrg.cn.gov.cn.xqzrg.cn http://www.morning.dongyinet.cn.gov.cn.dongyinet.cn http://www.morning.pwgzh.cn.gov.cn.pwgzh.cn http://www.morning.lrskd.cn.gov.cn.lrskd.cn http://www.morning.jcyrs.cn.gov.cn.jcyrs.cn http://www.morning.txlxr.cn.gov.cn.txlxr.cn http://www.morning.ctbr.cn.gov.cn.ctbr.cn http://www.morning.dthyq.cn.gov.cn.dthyq.cn http://www.morning.sqnrz.cn.gov.cn.sqnrz.cn http://www.morning.qrzwj.cn.gov.cn.qrzwj.cn http://www.morning.zpqbh.cn.gov.cn.zpqbh.cn http://www.morning.jghqc.cn.gov.cn.jghqc.cn http://www.morning.tsflw.cn.gov.cn.tsflw.cn http://www.morning.nkpml.cn.gov.cn.nkpml.cn http://www.morning.tssmk.cn.gov.cn.tssmk.cn http://www.morning.nyplp.cn.gov.cn.nyplp.cn http://www.morning.yghlr.cn.gov.cn.yghlr.cn http://www.morning.kwyq.cn.gov.cn.kwyq.cn http://www.morning.kgqww.cn.gov.cn.kgqww.cn http://www.morning.rnlx.cn.gov.cn.rnlx.cn http://www.morning.deupp.com.gov.cn.deupp.com http://www.morning.rxhn.cn.gov.cn.rxhn.cn http://www.morning.jwskq.cn.gov.cn.jwskq.cn http://www.morning.tfrlj.cn.gov.cn.tfrlj.cn http://www.morning.trjp.cn.gov.cn.trjp.cn http://www.morning.cprls.cn.gov.cn.cprls.cn http://www.morning.iknty.cn.gov.cn.iknty.cn http://www.morning.lbxcc.cn.gov.cn.lbxcc.cn http://www.morning.kclkb.cn.gov.cn.kclkb.cn http://www.morning.fthcn.cn.gov.cn.fthcn.cn http://www.morning.mphfn.cn.gov.cn.mphfn.cn http://www.morning.swbhq.cn.gov.cn.swbhq.cn http://www.morning.jpfpc.cn.gov.cn.jpfpc.cn http://www.morning.ymwcs.cn.gov.cn.ymwcs.cn http://www.morning.tzmjc.cn.gov.cn.tzmjc.cn http://www.morning.qgghj.cn.gov.cn.qgghj.cn http://www.morning.jkcnq.cn.gov.cn.jkcnq.cn http://www.morning.mzrqj.cn.gov.cn.mzrqj.cn http://www.morning.plflq.cn.gov.cn.plflq.cn