当前位置: 首页 > news >正文

做的网站打印全乱掉了网站开发应该注意什么

做的网站打印全乱掉了,网站开发应该注意什么,什么网站类型,wordpress手机滑动导航菜单目录 1.类的6个默认成员函数 2. 构造函数 2.1 构造函数的概念 2.2 构造函数的特性 3. 析构函数 3.1 析构函数的概念 3.2 析构函数的特性 4.拷贝构造函数 4.1 拷贝构造函数的概念 4.2 拷贝构造函数的特性 5.赋值运算符重载函数 5.1运算符重载函数 5.2 赋值运算符重…目录 1.类的6个默认成员函数  2. 构造函数 2.1 构造函数的概念 2.2 构造函数的特性 3. 析构函数 3.1 析构函数的概念 3.2 析构函数的特性 4.拷贝构造函数 4.1 拷贝构造函数的概念 4.2 拷贝构造函数的特性 5.赋值运算符重载函数 5.1运算符重载函数 5.2 赋值运算符重载函数 5.3 前置和后置重载 前置 后置 6.取地址操作符重载函数和const取地址操作符重载函数 1.类的6个默认成员函数  如果一个类中什么成员都没有简称为空类。可是空类中真的什么都没有吗 其实并不是的任何类在什么都不写时编译器会自动生成以下6个默认成员函数。 默认成员函数用户没有显式实现编译器会生成的成员函数称为默认成员函数。 类的6个默认成员函数编译器都会自己生成如果编译器生成的默认成员函数能够满足我们的需求我们就无需再自己实现 相反如果编译器生成的默认成员函数不能满足我们的需求我们就必须要自己实现了。 本篇博客正是介绍类的这6个默认成员函数都有哪些特性讲述什么情况下只需使用默认成员函数什么情况下需要自己实现以及要怎样实现的问题 2. 构造函数 2.1 构造函数的概念 如下代码我们定义一个日期类并且调用成员函数 #include iostream using namespace std;class Data { 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() {Data d1;d1.Init(2023, 5, 23);d1.Print();Data d2;d2.Init(2022, 5, 23);d2.Print();return 0; } 按照我们之前学过的按部就班地先调用初始化成员函数再调用打印成员函数运行结果也中规中矩地跑出来了。 可是有一天我需要很多个Data变量写代码又太急躁在创建某个Data变量时忘记调用Init成员函数了如下所示 #include iostream using namespace std;class Data { 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() {Data d1;d1.Init(2023, 5, 23);d1.Print();Data d2;d2.Print();return 0; } 结果d2出现了随机值 通过以上赘述对于Data类可以通过Init公有方法给对象设置日期如果忘记一次初始化就会导致bug的产生那就不得不每次创建对象时都调用该方法设置信息可是这样是不是有些太麻烦了呢有没有方法在对象创建时就将对象设置进去呢 答案当然是有的这就引出了C的1个默认成员函数——构造函数 构造函数是一个特殊的成员函数名字与类名相同,创建类类型对象时由编译器自动调用以保证每个数据成员都有一个合适的初始值并且在对象整个生命周期内只调用一次。 2.2 构造函数的特性 构造函数是特殊的成员函数需要注意的是构造函数没有用我们经常熟悉的Init来命名虽然名称叫构造但是构造函数的主要任 务并不是开空间创建对象而是初始化对象。 其特征如下 1. 函数名与类名相同 2. 无返回值 3. 对象实例化时编译器自动调用对应的构造函数 4. 构造函数可以重载 验证如下 #include iostream using namespace std;class Data { public://退出历史舞台/*void Init(int year, int month, int day){_year year;_month month;_day day;}*///1. 函数名与类名相同2. 无返回值Data(int year, int month, int day){_year year;_month month;_day day;}//4. 构造函数可以重载Data(){_year 8;_month 8;_day 8;}void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; };int main() {//调用含参构造函数Data d1(2023, 5, 23); //3. 对象实例化时编译器自动调用对应的构造函数d1.Print();//调用无参构造函数Data d2; //注意这里不能用诸如Data d2不能加因为会与函数声明产生歧义d2.Print();return 0; } 当然这里也完全可以用到缺省参数 #include iostream using namespace std;class Data { public:Data(int year 8, int month 8, int day 8){_year year;_month month;_day day;}void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; };int main() {Data d1(2023, 5, 23); d1.Print();Data d2(2023, 5);d2.Print();Data d3;d3.Print();return 0; } 5. 如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显式定义编译器将不再生成。 代码验证如下 #include iostream using namespace std;class Data { public:如果显示定义编译器将不再生成//Data(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() {Data d1;d1.Print();return 0; } 将Date类中构造函数屏蔽后代码可以通过编译因为编译器生成了一个无参的默认构造函数 将Date类中构造函数放开代码编译失败因为一旦显式定义任何构造函数编译器将不再生成无参构造函数放开后报错error C2512: “Date”: 没有合适的默认构造函数可用 这时你可能要问了 在不显示定义构造函数的情况下编译器会生成默认的构造函数。但是看起来默认构造函数似乎并没有什么用处呀 上面d1对象调用了编译器生成的默认构造函数但是d1的对象_year/_month/_day结果显示依旧是随机值上面的运行结果就是铁铮铮的事实呀这不是恰恰证明了这里编译器生成的默认构造函数并没有什么卵用吗 这就涉及到了构造函数的第6个特性 6.C把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型如int/char...自定义类型就是我们使用class/struct/union等自己定义的类型编译器生成默认的构造函数会对自定义类型成员调用的它的默认成员函数而内置类型则不做处理。 代码验证如下 #include iostream using namespace std;class Time { public:Time(){cout Time() endl;_hour 0;_minute 0;_second 0;} private:int _hour;int _minute;int _second; }; class Date {public: void Print() {cout _year - _month - _day endl; } private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t; }; int main() {Date d;d.Print();return 0; } 说到这里我又有些不解同样都是变量为什么还要分自定义类型调用它的默认成员函数内置类型却不做处理呢这难道不是一件画蛇添足的事情吗 这次不否定了说的确实有道理所以在C11 中针对内置类型成员不初始化的缺陷又打了补丁即内置类型成员变量在类中声明时可以给默认值。 代码验证如下 #include iostream using namespace std; class Time { public:Time(){cout Time() endl;_hour 0;_minute 0;_second 0;} private:int _hour;int _minute;int _second; }; class Date { public:void Print(){cout _year - _month - _day endl;} private:// 基本类型(内置类型)// C11支持声明时给缺省值int _year 2023;int _month 5;int _day 23;// 自定义类型Time _t; }; int main() {Date d;d.Print();return 0; } 思考如下代码能否正常运行 #include iostream using namespace std; class Date { public:Date(){_year 2023;_month 5;_day 23;}Date(int year 2023, int month 5, int day 23){_year year;_month month;_day day;} private:int _year;int _month;int _day; }; // 以下测试函数能正常运行吗 void Test() {Date d1; }答案是否定的 针对以上现象可以引出构造函数的第7个特性 7.无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个。 注意无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数都可以认为是默认构造函数。  3. 析构函数 3.1 析构函数的概念 通过上面构造函数的学习我们知道一个对象是怎么来的那一个对象又是怎么没的呢这就需要我们学习析构函数了 析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作。 3.2 析构函数的特性 析构函数也是特殊的成员函数其特征如下 1. 析构函数名是在类名前加上字符 ~ 2. 无参数无返回值类型 3. 一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数。注意与构造函数不同的是析构函数不能重载 4. 对象生命周期结束时C编译系统自动调用析构函数 #include iostream using namespace std;class Data { public:Data(int year 2023, int month 5, int day 23){_year year;_month month;_day day;}void Ptint(){cout _year - _month - _day endl;}//1. 析构函数名是在类名前加上字符 ~2. 无参数无返回值类型~Data(){cout ~Data endl;}private:int _year;int _month;int _day; }; int main() {Data d;d.Ptint();//这里为调用~Data4. 对象生命周期结束时C编译系统自动调用析构函数return 0; } 当然Data类并不需要析构函数这里只是为了证明C自动调用了析构函数。 我们将析构函数用到顺序表中可能会对析构函数有更深刻的理解 #include iostream using namespace std;typedef int DataType;class SeqList { public:SeqList(){cout 已经调用了SeqList()构造函数 endl;_a (DataType*)malloc(sizeof(DataType) * 4);if (_a nullptr){perror(malloc failed);//如果扩容失败说明原因exit(-1);}_size 0;//当size≥capacity时就动态开辟空间_capacity 4;//初始化数组容量为4}~SeqList(){cout 已经调用了~SeqList()析构函数 endl;free(_a);_a nullptr;_size _capacity 0;}private:int* _a;int _size;int _capacity; };int main() {SeqList sl;return 0; } 对于第3条特性系统自动生成默认的析构函数会不会完成一些事情呢 5. 答案与构造函数相似编译器生成的默认析构函数对自定义类型成员调用它的析构函数而内置类型则不做处理。 代码验证如下 #include iostream using namespace std;class Time { public:~Time(){cout 已经调用了~Time()析构函数 endl;} private:int _hour;int _minute;int _second; }; class Date { private:// 基本类型(内置类型)int _year 2023;int _month 5;int _day 23;// 自定义类型Time _t; }; int main() {Date d;return 0; } 运行结果为 对以上结果和第3、第5条特性的详细解释 程序运行结束后输出“已经调用了~Time()析构函数”在main中根本没有直接创建Time类的对象为什么最后会调用Time类的析构函数 因为main中创建了Date对象d而d中包含4个成员变量其中_year, _month, _day三个是内置类型成员销毁时不需要资源清理最后系统直接将其内存回收即可 而_t是Time类对象所以在d销毁时要将其内部包含的Time类的_t对象销毁所以要调用Time类的析构函数 但是main函数中不能直接调用Time类的析构函数实际要释放的是Date类对象所以编译器会调用Date类的析构函数而Date没有显式提供则编译器会给Date类生成一个默认的析构函数目的是在其内部调用Time类的析构函数 即当Date对象销毁时要保证其内部每个自定义对象都可以正确销毁main函数中并没有直接调用Time类析构函数而是显式调用编译器为Date类生成的默认析构函数 注意创建哪个类的对象则调用该类的构造函数销毁哪个类的对象则调用该类的析构函数 6. 如果类中没有申请资源时析构函数可以不写直接使用编译器生成的默认析构函数比如 Date类有资源申请时一定要写否则会造成资源泄漏比如SeqList类。  4.拷贝构造函数 4.1 拷贝构造函数的概念 电视剧中以及现实中双胞胎的例子不在少数我们甚至可以说简直他们就是一个模子里刻出来的那么在创建对象时可否创建一个与已存在对象一某一样的新对象呢答案的肯定的。 拷贝构造函数只有单个形参该形参是对本类 类型对象的引用(一般常用const修饰)在用已存在的类 类型对象创建新对象时由编译器自动调用。 4.2 拷贝构造函数的特性 1. 拷贝构造函数是构造函数的一个重载形式。即拷贝构造函数是一个特殊的构造函数 2. 拷贝构造函数的参数只有一个且必须是类 类型对象的引用使用传值方式编译器直接报错因为会引发无穷递归调用 代码验证如下 不考虑特性2我们偏偏就要直接传值调用 #include iostream using namespace std; class Date { public:Date(int year 2023, int month 7, int day 7){_year year;_month month;_day day;}Date( Date d) {_year d._year;_month d._month;_day d._day;}void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; }; int main() {Date d1;d1.Print();Date d2(d1);d2.Print();return 0; } 会发现程序报错 这是为什么呢答案就像特征2中所说的在此过程中引发了无穷递归调用 当我们直接传值调用时会发生先传值再调用拷贝构造函数的情况即 所以正确应该如特性2所说的那样 #include iostream using namespace std; class Date { public:Date(int year 2023, int month 7, int day 7){_year year;_month month;_day day;}// Date( Date d) // 错误写法编译报错会引发无穷递归Date( Date d) // 正确写法{_year d._year;_month d._month;_day d._day;}void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; }; int main() {Date d1;d1.Print();Date d2(d1);d2.Print();return 0; } 那么在概念中又提到:(一般常用const修饰),这是为什么呢 这是为了防止我们在定义拷贝构造函数时写反了 Date( Date d) {d._year _year;d._month _month;d._day _day;} 那么运行结果不但不会正确反而会偷鸡不成蚀把米 所以加上const即使出现了这样的低级错误编译器就会报错我们也能及时发现 Date( const Date d) {d._year _year;d._month _month;d._day _day;} 正确代码 #include iostream using namespace std; class Date { public:Date(int year 2023, int month 7, int day 7){_year year;_month month;_day day;}// Date( Date d) // 错误写法编译报错会引发无穷递归Date( const Date d) // 正确写法{_year d._year;_month d._month;_day d._day;}void Print(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; }; int main() {Date d1;d1.Print();Date d2(d1);d2.Print();return 0; } 3.与构造函数和析构函数相似若未显式定义编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。 在编译器生成的默认拷贝构造函数中内置类型是按照字节方式直接拷贝的而自定义类型是调用其拷贝构造函数完成拷贝的。 代码验证如下 #include iostream using namespace std; class Time { public:Time(){_hour 8;_minute 8;_second 8;}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 { public:void Print(){cout _year - _month - _day endl;} private:// 基本类型(内置类型)int _year 2023;int _month 7;int _day 7;// 自定义类型Time _t; }; int main() {Date d1;// 用已经存在的d1拷贝构造d2此处会调用Date类的拷贝构造函数// 但Date类并没有显式定义拷贝构造函数则编译器会给Date类生成一个默认的拷贝构造函数Date d2(d1);d2.Print();return 0; } 与前面的构造函数和析构函数相似的问题编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了还需要自己显式实现吗 当然像上面的Data类这样的类是没必要的。那么像顺序表之类的类呢验证如下 #include iostream using namespace std;typedef int DataType;class SeqList { public:SeqList(){cout 已经调用了SeqList()构造函数 endl;_a (DataType*)malloc(sizeof(DataType) * 4);if (_a nullptr){perror(malloc failed);//如果扩容失败说明原因exit(-1);}_size 0;//当size≥capacity时就动态开辟空间_capacity 4;//初始化数组容量为4}//打印void Print(){for (int i 0; i _size; i){cout _a[i] endl;}}//尾插void PushBack(const DataType x){_a[_size] x;_size;}~SeqList(){cout 已经调用了~SeqList()析构函数 endl;free(_a);_a nullptr;_size _capacity 0;}private:int* _a;int _size;int _capacity; };int main() {SeqList sl1;sl1.PushBack(1);sl1.PushBack(2);sl1.PushBack(3);sl1.PushBack(4);sl1.Print();SeqList sl2(sl1);sl2.Print();return 0; } 运行结果如图 我们可以看到程序崩溃了这是为什么呢 打开监视窗口看一下sl1和sl2的内存地址 发现二者的地址相同所以我们就知道了  1.sl1对象调用构造函数创建在构造函数中申请了_capacity4个元素的空间然后里面存储了4个元素1 2 3 4 2. sl2对象使用sl1对象拷贝构造而SeqList类没有显示定义拷贝构造函数则编译器会给SeqList类生成一份默认的拷贝构造函数默认拷贝构造函数是按照值拷贝的即将sl1中的内容原封不动地拷贝到sl2中。因此sl1与sl2指向了同一块内存空间 3. 当程序退出时sl2和sl1要销毁。sl2先销毁sl2销毁时调用析构函数已经将0x00b59580的空间释放了但是sl1并不知道到sl1销毁时会将0x00b59580的空间再释放一次正如3.2的第5条特性说的那样一块内存空间多次释放必然会导致bug的产生。 现在我已经知道原因了那么正确的代码应该怎么写呢这就需要用到深拷贝去解决关于深拷贝后面会有详解 //自定义拷贝构造函数不用编译器默认生成的深拷贝SeqList( const SeqList sl){_a (DataType*)malloc(sizeof(DataType) * 4);//我也开辟一个空间if (_a nullptr){perror(malloc failed);//如果扩容失败说明原因exit(-1);}memcpy(_a, sl._a, sizeof(int) * sl._capacity);_size sl._size;_capacity sl._capacity;} 所以我们应该要明白 4.类中如果没有涉及资源申请时拷贝构造函数是否写都可以一旦涉及到资源申请 时则拷贝构造函数是一定要写的否则就是浅拷贝。 5.赋值运算符重载函数 5.1运算符重载函数 在学习赋值运算符重载之前我们先来了解一下运算符重载 通过上面的学习我们已经知道了内置类型和自定义类型的区别思考这样一个问题 显而易见内置类型对象可以直接用各种运算符内置类型是语言自己定义的编译直接转换成指令 举个简单的例子内置类型的int类型2和1编译器可以轻松知道21内置类型的double类型2.2和1.1,编译器轻松知道2.21.1,诸如此类...... 那么问题来了我们通篇写的Data类对象我这时候需要判断2012年7月7日与2013年7月7日哪个日期更大编译器能直接判断出2012年7月7日2013年7月7日吗显然是不能的因为自定义类型编译器不支持直接转换成指令。 那么这时候就需要我们自己写一个函数来实现 写一个大于比较函数 bool Greater(Data d1, Data d2) {if (d1._year d2._year){return true;}else if (d1._year d2._year d1._month d2._month){return true;}else if (d1._year d2._year d1._month d2._month d1._day d2._day){return true;}return false; } 再比如我写一个等于比较的函数 bool Equal(Data d1, Data d2) {return d1._year d2._year d1._month d2._month d1._day d2._day; } 运行一下 #include iostream using namespace std; class Data { public:Data(int year 2012, int month 7, int day 7){_year year;_month month;_day day;}Data(const Data d){_year d._year;_month d._month;_day d._day;}void Ptint(){cout _year - _month - _day endl;}//private:int _year;int _month;int _day; };//布尔类型bool用于表示真true和假false的值。 //它只有两个取值true 和 false分别对应 1 和 0 。 bool Greater(Data d1, Data d2) {if (d1._year d2._year){return true;}else if (d1._year d2._year d1._month d2._month){return true;}else if (d1._year d2._year d1._month d2._month d1._day d2._day){return true;}return false; }bool Equal(Data d1, Data d2) {return d1._year d2._year d1._month d2._month d1._day d2._day; }int main() {Data d1(2013, 7, 7);Data d2(2012, 7, 7);cout Greater(d1, d2) endl;cout Equal(d1, d2) endl; return 0; } 说到这里我们来说一个题外话关于函数的命名其实在C语言中我们就遇到过很多了一个函数命名就如同给自己的孩子取名字一样比如上面的判断大于和判断相等函数我能用Greater、Equal为什么就不能用DaYu、DengYu或者Compare1、Compare2又或者func1、func2呢 这些确实都是可以的呀我创建的函数我乐意怎样取名我就怎样取名 可是话说回来你的孩子在你口中叫狗蛋儿、在老师口中叫张三有一天你去开家长会老师问你是谁的家长你说你是狗蛋儿的家长你这样说老师会知道张三就是狗蛋儿狗蛋儿就是张三吗 话再说回来你写的函数叫DaYu、DengYu而你的同事要用这个函数你写的DaYu、DengYu同事能知道这是个什么函数吗 所以为了规避这种情况增强代码的可读性C引入了运算符重载运算符重载是具有特殊函数名的函数也具有返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 函数名字为关键字operator后面接需要重载的运算符符号。 函数原型返回值类型 operator操作符(参数列表) 因此上述两个函数就可以写为更加规范我们加上const和 //bool Greater(Data d1, Data d2) bool operator(const Data d1, const Data d2) {if (d1._year d2._year){return true;}else if (d1._year d2._year d1._month d2._month){return true;}else if (d1._year d2._year d1._month d2._month d1._day d2._day){return true;}return false; }//bool Equal(Data d1, Data d2) bool operator (const Data d1, const Data d2) {return d1._year d2._year d1._month d2._month d1._day d2._day; } int main() {Data d1(2013, 7, 7);Data d2(2012, 7, 7);/*cout Greater(d1, d2) endl;cout Equal(d1, d2) endl; */cout operator (d1, d2) endl;cout operator (d1, d2) endl;return 0; } 以及为了令自定义类型更贴合与内置类型一样让编译器自己计算直接转为指令 int main() {Data d1(2013, 7, 7);Data d2(2012, 7, 7);/*cout Greater(d1, d2) endl;cout Equal(d1, d2) endl; *//*cout operator (d1, d2) endl;cout operator (d1, d2) endl;*/bool ret1 d1 d2; //d1d2吗是为1否为0bool ret2 d1 d2; //d1d2吗是为1否为0int a 3 2; //32吗是为1否为0int b 3 2; //32吗是为1否为0cout ret1 endl ret2 endl;cout a endl b endl;return 0; } 仔细观察我们上面写的Data类可以发现我把private注释掉了那现在我把注释关掉 成员变量变私有了该怎么办呢其实C常用的解决方法是直接将函数放到类里面因为类里面可以随便访问private class Data { public:Data(int year 2012, int month 7, int day 7){_year year;_month month;_day day;}Data(const Data d){_year d._year;_month d._month;_day d._day;}bool operator (const Data d1, const Data d2){return d1._year d2._year d1._month d2._month d1._day d2._day;}void Ptint(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; }; 可是这样写发现还是编译不通过 它说函数参数太多我放到类外面参数就不多怎么放到类里面就多参数了呢 对因为存在一个隐含的this指针详细请看C入门2——类与对象1中的3所以这时就可以这样修改 class Data { public:Data(int year 2012, int month 7, int day 7){_year year;_month month;_day day;}Data(const Data d){_year d._year;_month d._month;_day d._day;}bool operator(const Data d2){if (_year d2._year){return true;}else if (_year d2._year _month d2._month){return true;}else if (_year d2._year _month d2._month _day d2._day){return true;}return false;}bool operator ( const Data d2){return _year d2._year _month d2._month _day d2._day;}void Ptint(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; };那么在函数调用时编译器就会帮我们负重前行 int main() {Data d1(2013, 7, 7);Data d2(2012, 7, 7);bool ret1 d1 d2; //d1.operator(d2)---d1.operator(d1,d2)bool ret2 d1 d2; //d1.operator(d2)---d1.operator(d1,d2)cout ret1 endl ret2 endl;return 0; } 所以运算符重载归纳有以下特点 1. 不能通过连接其他符号来创建新的操作符比如operator 2. 重载操作符必须有一个类类型参数 3. 用于内置类型的运算符其含义不能改变例如内置的整型不能改变其含义 4. 作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐藏的this 5.  .*    ::     sizeof     ?:     .    以上5个运算符不能重载。 5.2 赋值运算符重载函数 铺了那么多前戏终于来到我们要学习的赋值运算符重载函数了 我们知道拷贝构造就是将一个已经初始化的变量A拷贝到未初始化的变量B中 那么如果存在两个都已经初始化的变量A、B我想把A的值拷贝到B显然就不能再用拷贝构造了要用到我们就要开始讲的赋值运算符重载 1. 赋值运算符重载格式 参数类型const T传递引用可以提高传参效率 返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值检测是否自己给自己赋值 返回*this 要复合连续赋值的含义 详解精华都在代码里 #include iostream using namespace std; class Data { public:Data(int year 2012, int month 7, int day 7){_year year;_month month;_day day;}Data(const Data d){_year d._year;_month d._month;_day d._day;}//d1d2;d1传给thisd2传给d//返回值应该是什么类型呢当然是Data类型应该返回d1的地址所以用引用返回Data operator(const Data d){//判断是否为自己给自己赋值放到这里不是引用是取地址//判断d2的地址是否与d1地址相等if (this ! d){_year d._year;_month d._month;_day d._day;}return *this;//返回d1的地址}void Ptint(){cout _year - _month - _day endl;}private:int _year;int _month;int _day; };int main() {Data d1(2023, 7, 7);Data d2(2022, 8, 8);//拷贝构造一个已经存在的对象去拷贝初始化另一个对象Data d3(d2);d1.Ptint();d2.Ptint();d3.Ptint();cout endl;//赋值运算符重载两个已经存在的对象拷贝d1 d2;//运算自定义类型就要用到运算符重载operatord1.Ptint();d2.Ptint();d3.Ptint(); } 2. 赋值运算符只能重载成类的成员函数不能重载成全局函数 原因赋值运算符如果不显式实现编译器会生成一个默认的。此时用户再在类外自己实现 一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突了故赋值 运算符重载只能是类的成员函数。 3. 用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。注意内置类型成员变量是直接赋值的而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。  4.如果类中未涉及到资源管理赋值运算符是否实现都可以一旦涉及到资源管理则必 须要实现。 这些特性与拷贝构造函数有极大的相似性这里不再过多赘述。 5.3 前置和后置重载 在C语言中我们已经知道了前置先加后用后置先用后加 这样的基本常识 那么我们学了运算符重载现在我要自定义类型Data前置和后置要怎么定义和实现呢 前置 前置为先1后使用所以前置的返回值应该是返回1之后的结果 故前置重载函数的实现为 // 前置返回1之后的结果Date operator()//返回d1所以返回值类型当然为Date类型{_day 1;return *this;//this指向的对象函数结束后不会销毁故以引用方式返回提高效率} 后置 后置为先使用后1所以后置的返回值应该为1之前的旧值故需在实现时需要先将this保存一份然后给this1 那么问题来了前置和后置都是一元运算符实现起来两个函数名字相同都是operator怎么才能区分这两个函数呢 为了让前置与后置形成能正确重载C规定后置重载时多增加一个int类型的参数但调用函数时该参数不用传递编译器自动传递 故后置重载函数的实现为 Date operator(int){Date temp(*this);// 先将this保存一份然后给this 1_day 1;return temp; // temp是临时对象出了作用域就会被销毁//因此只能以值的方式返回不能返回引用} 验证 #include iostream using namespace std; class Date { public:Date(int year 2023, int month 7, int day 7){_year year;_month month;_day day;}// 前置返回1之后的结果Date operator()//返回d1所以返回值类型当然为Date类型{_day 1;return *this;//this指向的对象函数结束后不会销毁故以引用方式返回提高效率}Date operator(int){Date temp(*this);// 先将this保存一份然后给this 1_day 1;return temp; // temp是临时对象出了作用域就会被销毁//因此只能以值的方式返回不能返回引用}void Print(){cout _year - _month - _day endl;} private:int _year;int _month;int _day; }; int main() {Date d1;Date d2(2022, 7, 7);d1 d2;//前置编译器默认调用不带int参数的operatord1.Print();d1 d2;//后置编译器默认调用带int参数的operatord1.Print();return 0; } 小知识在C语言中前置和后置二者的效率高低可能并不明显但是在C中一般来说前置的效率要高于后置 6.取地址操作符重载函数和const取地址操作符重载函数 终于来到类的最后两个默认成员成员函数了二者的形式为 class Date { public://取地址操作符重载Date* operator(){return this;}//const取地址操作符重载const Date* operator()const{return this;} private:int _year; // 年int _month; // 月int _day; // 日 };这两个默认成员函数一般不用重新定义 编译器默认会生成。 这两个运算符一般不需要重载使用编译器生成的默认取地址的重载即可只有特殊情况才需 要重载比如想让别人获取到指定的内容所以这里就不再过多介绍这两个默认成员函数。 本篇完
http://www.w-s-a.com/news/218439/

相关文章:

  • 移动网站如何做权重wordpress 统计字数 插件
  • 编写网站的软件百度指数教程
  • 网站改版建议策划书做设计什么兼职网站
  • 北京做兼职网站文创产品设计流程
  • 南阳做玉器网站wordpress 图片被缩小
  • 自己做网站卖衣服cms做网站容易不
  • 安徽安搜做的网站怎么样手机网站商城建设答辩问题
  • 分析不同网站的优缺点房产网站定制
  • 深圳工业设计大展2021论坛与网站做优化哪个更好
  • 什么网站做招聘比较好网络营销渠道管理
  • 网站建设选择什么模式淘宝网站可以做轮播吗
  • 山西免费网站制作乌市高新区建设局网站
  • 公司网站建设费用会计处理手机app免费下载
  • 网站的做网站的公司网站有些什么内容
  • 网站新类型wordpress 随机文章
  • 电商网站建设会计分录朝阳市网站公司
  • 正邦网站建设 优帮云百姓网征婚
  • 企业网站有哪些举几个例子端午节网站建设目的
  • 南京免费发布信息网站网站建设与管理职责
  • 无锡市建设培训中心网站企业vi设计是啥
  • 宿松网站建设推荐秒搜科技国家官方网站
  • 网站的服务器选择wordpress文章底部加分享
  • 天津专业的网站建设公司阿里云服务器 wordpress
  • 家教辅导培训网站建设中东跨境电商平台有哪些
  • 商城形式的网站需要多少钱做医药商城网站的公司吗
  • 贵阳网站设计zu97彩票创建网站
  • 网站建设与分工的论文足球世界排名
  • 网站首页添加标签如何用模板建站
  • 官方网站包括哪几个网站泰安的网站建设公司哪家好
  • 域名虚拟服务器做网站如何搭建企业网站