C++:类中的赋值函数
先来看一个例子:
1 #include<iostream>2 #include<string>3 using namespace std;4 class Student{5 public:6 Student(){7 cout<<"调用默认构造函数"<<endl;8 };9 Student(string name,int age,string gender):Name(name),Age(age),Gender(gender){ 10 //cout<<"调用构造函数1"<<endl; 11 } 12 Student(const Student& stu){//拷贝构造函数 13 Name=stu.Name; 14 Age=stu.Age; 15 Gender=stu.Gender; 16 cout<<"调用拷贝构造函数"<<endl; 17 } 18 ~Student(){ 19 //cout<<"调用析构函数"<<endl; 20 } 21 void show(){ 22 cout<<"Name:"<<Name<<endl; 23 cout<<"Age:"<<Age<<endl; 24 cout<<"Gender:"<<Gender<<endl; 25 } 26 private: 27 string Name; 28 int Age; 29 string Gender; 30 }; 31 32 int main(){ 33 Student stu("Tomwenxing",23,"male"); 34 Student stu2("Ellen",24,"female"); 35 cout<<"---------------------赋值操作之前-----------------"<<endl; 36 stu2.show(); 37 cout<<"---------------------赋值操作之后-----------------"<<endl; 38 stu2=stu; 39 stu2.show(); 40 return 0; 41 }
由上面的例子可以看出,C++支持自定义类型的对象之间的赋值操作,而赋值功能的实现则主要依靠自定义类中的赋值函数。每一个自定义类中都有且只有一个赋值函数,该赋值函数既可以由编译器隐式地定义在自定义类中,也可以有用户通过对赋值运算符=的重载显式地定义在自定义类中:
1 #include<iostream>2 #include<string>3 using namespace std;4 class Student{5 public:6 Student(){7 cout<<"调用默认构造函数"<<endl;8 };9 Student(string name,int age,string gender):Name(name),Age(age),Gender(gender){ 10 //cout<<"调用构造函数1"<<endl; 11 } 12 Student(const Student& stu){//拷贝构造函数 13 Name=stu.Name; 14 Age=stu.Age; 15 Gender=stu.Gender; 16 cout<<"调用拷贝构造函数"<<endl; 17 } 18 ~Student(){ 19 //cout<<"调用析构函数"<<endl; 20 } 21 Student& operator=(const Student& stu){ //赋值函数 22 cout<<"调用类中的赋值函数"<<endl; 23 if(this!=&stu){ 24 Name=stu.Name; 25 Age=stu.Age; 26 Gender=stu.Gender; 27 } 28 return *this; 29 } 30 void show(){ 31 cout<<"Name:"<<Name<<endl; 32 cout<<"Age:"<<Age<<endl; 33 cout<<"Gender:"<<Gender<<endl; 34 } 35 private: 36 string Name; 37 int Age; 38 string Gender; 39 }; 40 41 int main(){ 42 Student stu("Tomwenxing",23,"male"); 43 Student stu2("Ellen",24,"female"); 44 cout<<"---------------------赋值操作之前-----------------"<<endl; 45 stu2.show(); 46 cout<<"---------------------赋值操作之后-----------------"<<endl; 47 stu2=stu; 48 stu2.show(); 49 return 0; 50 }
特别注意:
Question 1:类中的赋值函数中的参数为什么加const?
Answer:参数使用cosnt的原因有两个:
• 防止类中的赋值函数对用来赋值的“原对象”进行修改
1 Student& Student::operator=(Student& stu){2 cout<<"调用类中的赋值函数"<<endl;3 if(this!=&stu){ 4 stu.Name="none";//错误,对用来赋值的“原对象”进行了修改5 stu.Age=0;//错误6 stu.Gender="none";//错误 7 Name=stu.Name;8 Age=stu.Age;9 Gender=stu.Gender; 10 } 11 return *this; 12 }
•若赋值函数的形参加上const,则赋值函数接受的实参对象既可以是const对象,也可以是非const对象;否则赋值函数能够接受的对象只能是非const对象,而不能是const对象。
1 Student& Student::operator=(Student& stu){2 cout<<"调用类中的赋值函数"<<endl;3 if(this!=&stu){4 Name=stu.Name;5 Age=stu.Age;6 Gender=stu.Gender;7 }8 return *this;9 } 10 int main(){ 11 const Student stu("Tomwenxing",23,"male"); 12 Student stu2("Ellen",24,"female"); 13 stu2=stu; //错误!不能将const对象赋值给非const对象 14 return 0; 15 }
Question 2:类中的赋值函数中的参数为什么使用引用?
Answer:避免调用类中的拷贝构造函数在内存中开辟空间来创建形参对象,而是让形参成为实参的别名,从而节省时间和空间,提供编程效率
1 Student& Student::operator=(const Student &stu){ //参数中使用引用 2 cout<<"调用类中的赋值函数"<<endl;3 if(this!=&stu){4 Name=stu.Name;5 Age=stu.Age;6 Gender=stu.Gender;7 }8 return *this;9 } 10 11 int main(){ 12 const Student stu("Tomwenxing",23,"male"); 13 Student stu2("Ellen",24,"female"); 14 stu2=stu; 15 return 0; 16 }
1 Student& Student::operator=(const Student stu){ //参数中没有使用引用 2 cout<<"调用类中的赋值函数"<<endl;3 if(this!=&stu){4 Name=stu.Name;5 Age=stu.Age;6 Gender=stu.Gender;7 }8 return *this;9 } 10 11 int main(){ 12 const Student stu("Tomwenxing",23,"male"); 13 Student stu2("Ellen",24,"female"); 14 stu2=stu; 15 return 0; 16 }
Question 3:类中的赋值函数的返回值类型为什么是Student&,不可以是Student或void吗?
Answer:在C++中,系统支持变量之间的连续赋值,如:
1 int a=10; 2 int b,c; 3 b=c=a;//变量之间的连续赋值,b、c的值均为10
其本质是先将变量a的值赋值给变量c,然后将赋值后的变量c返回到赋值运算符=的右边,再将其赋值给变量b,即:
1 int a=10; 2 b=(c=a); //即c=a,b=c;
同理,如果类中赋值函数的返回值类型为void,即类中的赋值函数没有返回值,此时编译器将不支持对该类中的对象进行连续赋值
1 void Student::operator=(const Student &stu){2 cout<<"调用类中的赋值函数"<<endl;3 if(this!=&stu){4 Name=stu.Name;5 Age=stu.Age;6 Gender=stu.Gender;7 }8 }9 int main(){ 10 const Student stu("Tomwenxing",23,"male"); 11 Student stu2("Ellen",24,"female"); 12 Student stu3; 13 stu3=stu2=stu; //错误!stu3=stu2=stu相当于stu3.operator=(stu2.operator=(stu)) ,由于赋值函数没有返回值,则该语句无法执行 14 return 0; 15 }
而赋值函数的返回值类型之所以是Student&而非Student是为了避免函数在返回对象时调用类中的拷贝构造函数在内存中创建临时对象,从而提高程序的运行效率
1 Student& Student::operator=(const Student& stu){ //返回值类型中使用引用& 2 cout<<"调用类中的赋值函数"<<endl;3 if(this!=&stu){4 Name=stu.Name;5 Age=stu.Age;6 Gender=stu.Gender;7 }8 return *this;9 } 10 11 int main(){ 12 Student stu("Tomwenxing",23,"male); 13 Student stu2; 14 stu2=stu; 15 return 0; 16 }
1 Student Student::operator=(const Student& stu){ //返回值类型中没有使用引用& 2 cout<<"调用类中的赋值函数"<<endl;3 if(this!=&stu){4 Name=stu.Name;5 Age=stu.Age;6 Gender=stu.Gender;7 }8 return *this;9 } 10 11 int main(){ 12 Student stu("Tomwenxing",23,"male"); 13 Student stu2; 14 stu2=stu; 15 return 0; 16 }
Question 4:语句“if(this!=&stu)”的作用是什么?
Answer:通过比较赋值者和被赋值者的地址是否相同来判断两者是否是同一个对象,从而避免自赋值(即自己给自己赋值)的情况的发生,原因如下:
• 为了提高程序的运行效率。自己给自己赋值是完全无意义的行为,只会浪费程序的时间资源。
• 当类中的数据成员中含有指针时,自赋值操作可能会带来灾难性的后果。例如假设对象a和b中都含有一个指针ptr,它们分别指向一块通过new动态开辟的内存空间A和内存空间B,当将对象a赋值给对象b时,要求先将对象b中指针ptr指向的内存空间B通过delete释放掉(否则将造成内存泄漏),然后在内存中重新开辟内存空间C以拷贝内存空间A中的内容,并让对象b的指针ptr重新指向内存空间C,从而完成赋值。如果此时允许对象的自赋值,那么对象会在自赋值前先释放自己指针所指的内存空间,然后重新在内存中开辟空间,然而由于之前的内存空间已经释放,此时新内存空间希望拷贝的内容将不复存在,因而造成灾难性后果。
因此,对于类中的赋值函数,一定要先检查是否是自赋值,如果是,直接return *this。
Question 5:自定义类的对象之间的赋值操作的本质是什么?
Answer:本质是调用类中的成员函数(operator=()函数)。如:
1 #include<iostream>2 #include<string>3 using namespace std;4 class Student{5 public:6 Student(){7 //cout<<"调用默认构造函数"<<endl;8 };9 Student(string name,int age,string gender):Name(name),Age(age),Gender(gender){ 10 //cout<<"调用构造函数1"<<endl; 11 } 12 Student(const Student& stu){//拷贝构造函数 13 Name=stu.Name; 14 Age=stu.Age; 15 Gender=stu.Gender; 16 cout<<"调用拷贝构造函数"<<endl; 17 } 18 ~Student(){ 19 //cout<<"调用析构函数"<<endl; 20 } 21 Student& operator=(const Student& stu){ //赋值函数 22 cout<<"调用类中的赋值函数"<<endl; 23 if(this!=&stu){ 24 Name=stu.Name; 25 Age=stu.Age; 26 Gender=stu.Gender; 27 } 28 return *this; 29 } 30 void show(){ 31 cout<<"\tName:"<<Name<<endl; 32 cout<<"\tAge:"<<Age<<endl; 33 cout<<"\tGender:"<<Gender<<endl; 34 } 35 private: 36 string Name; 37 int Age; 38 string Gender; 39 }; 40 41 int main(){ 42 Student stu("Tomwenxing",23,"male"); 43 Student stu2,stu3; 44 stu2=stu;//对stu2进行赋值 45 cout<<"对象stu2:"<<endl; 46 stu2.show(); 47 cout<<"------------分界线-------------------"<<endl; 48 stu3.operator=(stu);//对stu3进行赋值 49 cout<<"对象stu3:"<<endl; 50 stu3.show(); 51 return 0; 52 }
C++:类中的赋值函数相关推荐
- 模板类中使用友元函数的方式,派生类友元函数对基类的成员使用情况
在一般友元函数的前面加上 template<typename T),注意在函数的声明和定义处都要加这个模板 例如: //模板类,长方体类 template <typename Elemen ...
- C++学习笔记-----永远不要在派生类中改变虚函数的默认参数值
提到虚函数,我们就会自然而然的想到多态,但是当虚函数中存有默认参数值的时候,在派生类中重定义这个虚函数时不可以改变这个参数的值. 请看下面的例子: #include "stdafx.h&qu ...
- php method_exists 检测类中是否包括函数
2019独角兽企业重金招聘Python工程师标准>>> method_exists 检测类中是否包括函数 method_exists() 函数的语法如下: bool method_e ...
- python init函数可以外部调用么,如何从python类中调用外部函数
我试图收集通过套接字解析的数据.这是我的密码:import pickle import SocketServer class SocketReciever(SocketServer.BaseReque ...
- python如何定义自定义函数_python类中系统自定义函数
标签: python类 双下划线特殊函数 今天遇到python类内部系统以双下划线开头和结尾的情况,特去学习一部分的应用情况,顺便记录一下.python 的OOP编程中,每个类拥有一些系统特殊定义的函 ...
- 【吉大刘大有数据结构绿皮书】向LinkedList类中增加一个函数Contrary,功能为将其所有结点按相反次序链接。
题目 向LinkedList类中增加一个函数Contrary,功能为将其所有结点按相反次序链接. 思路 考研要求用C语言,那我就用C语言(没有面向对象),本题就是个链表倒置算法,先将哨位结点和后面的结 ...
- C++中模板类中的成员函数以及模板函数在类外定义
在C++中,类中的成员函数可以在类外完成定义,从而显得类中的成员函数看起来简洁明了.但是模板类里的成员函数和模板函数与普通的成员函数在类外定义不同. 先定义一个模板类以及成员函数和模板函数: 接下我们 ...
- 阿超记载类中的回调函数
类中的回调函数(收藏) #1 回调函数是函数的一种,都有一样的声明和定义格式. 回调函数是其他函数中的参数.也就是说其函数地址作为其他函数的参数. 我是这样理解的. 回调函数不同的地方有不同的使用方法 ...
- oop 类中定义 的函数_WordPress的高级OOP:自定义REST API端点
oop 类中定义 的函数 This article on advanced OOP for WordPress was originally published by Torque Magazine, ...
最新文章
- python视频抽帧 后 前端javascript如何显示_python通过ffmgep从视频中抽帧的方法
- CentOS 5 下yum安装 Mono 2.4
- Windows中使用Python和C/C++联合开发应用程序起步
- 经典|深入理解 Go高性能网络编程模型
- DataGridView动态添加新行的两种方法
- python相关函数_python列表相关函数
- JDBC解析9_UpdateWithResultSet
- 关于C语言goto的使用
- Xcode不能真机调试运行
- day7--pandas
- hibernate 数据分页显示 及 分页导航栏的设置
- e480win7显卡驱动_e480安装了windows7显卡驱动装不上
- ES的索引(倒排索引),文档,查询
- android开机固定程序,Android实现开机自启动某个程序
- 直击|知乎App增加视频回答入口 视频流归到问题下
- 阿里云快照如何恢复到另外一台服务器
- easyexcel 在 设置标题_七. EasyExcel标题加批注和标题字体填充红色
- Mn掺杂CdS量子点|锰掺杂硫化镉量子点|MnS/ZnS/CdS量子点的制备方法图示
- UVM-TLM机制解读
- Ubuntu自制liveCD学习
热门文章
- 程序员的中场职业规划
- 应用开发者必须了解的Kubernetes网络二三事
- 行为型模式:责任链模式
- 遇到的一些小的tips
- 【Python】青少年蓝桥杯_每日一题_1.27_单词出现的次数
- Java 洛谷 P1424 小鱼的航程(改进版)
- background-attachment: fixed的用法
- java logfaction_Java调试的变迁:从System.out.println到log4j
- columnproperty server sql_导出SQL Server数据库表中字段的说明/备注
- 数据中心机房常用通信管道塑料管材