第四章运算符重载
第04章 运算符重载
class A { int i; public: A(int a=0){ i=a;} void Show(void) {cout<<"i="<<i<<endl;} void AddA(A &a, A &b) // 利用函数进行类之间的运算 { i=a.i+b.i; } A operator +(A &a) // 重载运算符+ { A t; t.i=i+a.i; return t; } }; void main(void) { A a1(10),a2(20),a3; 相当于a3=a1.operator+(a2) a1.Show (); a2.Show (); a3=a1+a2; //重新解释了加法,可以直接进行类的运算 a3.AddA(a1,a2); //调用专门的功能函数 a3.Show (); }
总结:
重新定义运算符,由左操作符
调用右操作符。最后将函数返
回值赋给运算结果的对象。
由对象c1调用
若已有运算载Complex operator+ (Complex &c1, Complex &c2) ,那下面的表达式还 合法吗 c3=c2+12; // 这个表达式合法吗? int i=3+5; //这个表达式合法吗?
C++基础系列——运算符重载
C++基础系列——运算符重载1. 运算符重载简介所谓重载,就是赋予新的含义。
函数重载(Function Overloading)可以让⼀个函数名有多种功能,在不同情况下进⾏不同的操作。
同样运算符重载(Operator Overloading)可以让同⼀个运算符可以有不同的功能。
可以对 int、float、string 等不同类型数据进⾏操作<< 既是位移运算符,⼜可以配合 cout 向控制台输出数据也可以⾃定义运算符重载:class Complex{public:Complex();Complex(double real, double imag);Complex operator+(const Complex &a) const;void display() const;private:double m_real;double m_imag;};// ...// 实现运算符重载Complex Complex::operator+(const Complex &A) const{Complex B;B.m_real = this->m_real + A.m_real;B.m_imag = this -> m_imag + A.m_imag;return B;// return Complex(this->m_real + A.m_real, this->m_imag + A.m_imag);}int main(){Complex c1(4.3, 5.8);Complex c2(2.7, 3.7);Complex c3;c3 = c1 + c2; // 运算符重载c3.display();return 0;}运算结果7 + 9.5i运算符重载其实就是定义⼀个函数,在函数体内实现想要的功能,当⽤到该运算符时,编译器会⾃动调⽤这个函数,它本质上是函数重载。
第4讲 运算符重载(上)
重载函数作为类的友元函数
11
小结
C++规定,有的运算符(如赋值运算符、下标运算符、 C++规定,有的运算符(如赋值运算符、下标运算符、函数 规定 调用运算符)必须定义为类的成员函数, 调用运算符)必须定义为类的成员函数,有的运算符则不能 定义为类的成员函数(如流插入“<<” 定义为类的成员函数(如流插入“<<”和流提取运算符 >>” 类型转换运算符) “>>”、类型转换运算符) 一般将单目运算符重载为成员函数, 一般将单目运算符重载为成员函数,将双目运算符重载为 友元函数 说明: 有的C++编译系统( C++编译系统 6.0)没有完全实 说明: 有的C++编译系统(如Visual C++ 6.0)没有完全实 C++标准 它所提供不带后缀. 标准, 现C++标准,它所提供不带后缀.h的头文件不支持把成员函 数重载为友元函数。但是Visual C++所提供的老形式的带 数重载为友元函数。但是Visual C++所提供的老形式的带 后缀. 后缀.h的头文件可以支持此项功能
第4讲 运算符重载
4.1 运算符重载概念 4.2 重载运算符的规则
1
4.1 运算符重载概念
重载概念:用户根据自己需要对C++已提供的运算符 或函数的功能重新赋予新的含义,使之“一词多义”
函数重载:同一函数名可以实现不同的功能 运算符重载:同一运算符能实现不同的运算操作
2
生活中的重载概念
“杯具”一词重 杯具” 载
12
本讲重点
重载的概念:“双肩挑” 重载的方法: 重载的方法:运算符重载是通过定义函 数实现的 重载的规则:7+1
vc 04 运算符重载
于是: 于是:
string x,y; x=x+y; //表示串 和串 合并,放入串 表示串x 表示串 和串y 合并,放入串x
这就使对基本类型的预定义运算符" 的含义在串类中被扩展 这就使对基本类型的预定义运算符"+"的含义在串类中被扩展 为对串类对象的合并操作,即运算符"+"被重载. 为对串类对象的合并操作,即运算符" 被重载. 被重载 运算符重载应注意的几个问题: 运算符重载应注意的几个问题: 1,哪些运算符可以重载? 哪些运算符可以重载? 中除了下面四种运算符外, 在C++ 中除了下面四种运算符外,系统预定义的运算符都 能被重载. 能被重载.
string x,y;
那么, 实现两个串的合并. 那么,可以使用函数strcat(x,y)实现两个串的合并. 如果在表示字符串的类对象x, 的特定环境下,运算符" 使 如果在表示字符串的类对象 ,y 的特定环境下,运算符"+"使 用于类对象,能被解释为串对象x 的合并, 用于类对象,能被解释为串对象 和y 的合并,则编程就更方便 了.
例如:下边是运算符重载的另一个例子,程序实现了复数的加 例如:下边是运算符重载的另一个例子, 和减运算. 和减运算.
#include <iostream.h> class Complex { public: Complex() { real=imag=0.0; } Complex(double r) { real=r; imag=0.0; } Complex(double r,double i) { real=r; imag=i; } Complex operator+(const Complex& c); Complex operator-(const Complex& c); friend void print(const Complex& c); private: double real,imag; };
4第四章 运算符重载
const complex operator - (const complex &c) const; void display(); //输出复数 private: //私有数据成员 1.是为了堵塞a+b=c的漏洞。 double real; //复数实部 2. 3.是为了扩大适应性。 double imag; //复数虚部 };
17
[ ]运算符重载为成员函数
下标运算符[]可以重载: 重载形式为:operator[](int); 当 X x; 隐含调用。 x[y] 可被解释为: 显式调用。 x. operator [ ](y); 只能重载为成员函数,不能使用友元函数。 这个类显然是个‚数组类‛。
18
前置++和后置++重载为成员函数
9
使用
void main(){
complex c1(5,4),c2(2,10),c3; //三个复数类的对象 cout<<"c1="; cout<<"c2="; c1.display(); c2.display();
c3=c1-c2; //使用重载运算符完成复数减法 cout<<"c3=c1-c2="; c3.display(); 程序输出结果为:
这三个运算符是许多 教课书没有提到的。
唯一的一个三目运 算符不能重载。
3
运算符重载的基础
设计运算符重载函数,首先要了解运算符原本的运算语义。重
载函数要忠实遵守该运算符作用于基本数据类型时的语义,
并表现出自身所特有的性质。 例如:+ 、+= 、=、++(前)、++(后) ....
简述运算符重载的规则。
简述运算符重载的规则。
运算符重载是指可以为自定义的类类型或枚举类型定义新的含义和功能。
在
C++中,运算符重载遵循以下一般规则:
1. 运算符重载必须至少有一个操作数是用户自定义的类类型或枚举类型的对象,否则将无法重载。
2. 运算符重载可以作为成员函数或非成员函数来实现。
3. 对于成员函数的运算符重载,操作数的数量为运算符的操作数减去1。
例如,重载双目运算符时(如+、-、*等),成员函数需要接受一个参数,用于表示另一个操作数。
4. 对于非成员函数的运算符重载,所有操作数都作为参数传递给函数。
可以通过将重载运算符函数声明为友元函数来访问类的私有成员。
5. 对于重载一元运算符(如++、),如果是成员函数,则返回一个修改后的对象;如果是非成员函数,则返回一个新的对象。
6. 对于重载二元运算符(如+、-、*等),如果是成员函数,则一个对象被修改,另一个对象不变;如果是非成员函数,则返回一个新的对象。
7. 运算符重载不能改变原有运算符的优先顺序和结合性。
8. 运算符重载遵循函数重载的规则,即可以根据参数类型和参数数量进行重载,实现不同的功能。
需要注意的是,运算符重载应该遵循语义上的合理性并不滥用。
第4章 运算符重载
• 在C++中只能重载单目运算符、双目运算符及 不确定目数运算符“()”
下列运算符不能重载 . 类成员运算符 .* 成员指针运算符 :: 域解析运算符 ?: 条件表达式运算符 “#” (???) sizeof(???)
重载运算符有哪些限制?
(1) 不可臆造新的运算符。必须把重载运算符 限制在C++语言中已有的运算符范围内的允许 重载的运算符之中。 (2) 重载运算符坚持4个“不能改变”。 · 不能改变运算符操作数的个数; · 不能改变运算符原有的优先级; · 不能改变运算符原有的结合性; · 不能改变运算符原有的语法结构
用类的成员函数重载双目运算符
• 双目运算符重载为类的成员函数时,形参 表中有一个参数,以当前对象作为运算符 的左操作数,参数作为右操作数。
例4.4 双目运算符重载为类的成员函数示例。 // 声明整型类 class Integer { private: // 数据成员 int num; // 数据值 public: // 公有函数 Integer(int n = 0): num(n){ } // 构造函数 void Set(int n) { num = n; } // 设置数据值 int Get() const { return num; } // 返回数据值 Integer operator+(const Integer &a) const// 重载加法运算符“+” { return Integer(this->num + a.num); } }; int main() // 主函数main() { Integer i(6), j(9), k; // 定义整型对象 k = i + j; // 对整型对象求加法运算,i+j等价于i.operator+(j); cout<<i.Get()<<"+"<<j.Get()<<"="<<k.Get()<<endl;// 输出数值 system("PAUSE"); // 输出系统提示信息 程序运行时屏幕输出如下: return 0; // 返回值0, 返回操作系统 6+9=15 } 请按任意键继续. . .
运算符重载
24
运算符重载
思考:如果希望表达式i+c1有意义, 思考:如果希望表达式i+c1有意义,应该 i+c1有意义 如何定义重载运算符函数? 如何定义重载运算符函数?
friend Complex operator+(int &i,Complex &c); Complex operator+(int &i, Complex &c) {return Complex(i+c.real,c.imag);}
2
什么是运算符重载
代码分析: 代码分析: 例10.1 通过函数来实现复数 相加。 相加。
CCS E
3
运算符重载的方法
运算符重载的方法是定义一个重载运 算符的函数, 算符的函数,在需要执行被重载的运 算符时,系统就自动调用该函数, 算符时,系统就自动调用该函数,以 实现相应的运算。也就是说, 实现相应的运算。也就是说,运算符 重载是通过定义函数实现的。 重载是通过定义函数实现的。运算符 重载实质上是函数的重载。 重载实质上是函数的重载。
CCS E
21
运算符重载
如果将运算符重载函数作为成员函数, 如果将运算符重载函数作为成员函数, 它可以通过this this指针自由地访问本类 它可以通过this指针自由地访问本类 的数据成员, 的数据成员,因此可以少写一个函数 的参数。 的参数。但必须要求运算表达式第一 个参数(即运算符左侧的操作数) 个参数(即运算符左侧的操作数)是一 个类对象, 个类对象,而且与运算符函数的类型 相同。 相同。因为必须通过类的对象去调用 该类的成员函数,而且只有运算符重 该类的成员函数, 载函数返回值与该对象同类型, 载函数返回值与该对象同类型,运算 结果才有意义。 结果才有意义。
4 运算符重载
可以将+代表的操作看成一个函数:+为函数的名字,+操作的两个操 作数的类型即为函数形参的类型,+操作的结果的类型即为函数的返回 值类型。
北京化工大学 VC++ 教学课件
2
计算机系 江志英 jiangzy@
运算符重载的提出
C/C++中,每种基本数据类型的变量都可通过几种运算符来做相关计 算,如int型变量,它们可以同“+”,“-”,“*”,“/”等运算符 来做加法,减法,乘法,除法等。如:
4 5 6
常用运算符的重载
重载赋值运算符operator=
重载输入/输出运算符 << | >>
重载下标运算符operator[ ]
重载类型转换函数
北京化工大学 VC++ 教学课件
4
计算机系 江志英 jiangzy@
运算符重载的基本语法
运算符的使用和普通函数在语法上有所不同,但是可以将 运算符看作是一种特殊的函数,操作数是函数的参数,运 算结果是函数的返回值。
北京化工大学 VC++ 教学课件
14
计算机系 江志英 jiangzy@
// 重载运算符的使用示例 int main() { Byte a, b, *bp; +b; -b; ~b; bp = &b; !b; ++b; b++; --b; b--; } //end of main()
3
Vector vec1,vec2 vec1+vec2; vec1-vec2; vec1*vec2; vec1/vec2; 两个向量类对象的加减乘除
C++提供了运算符重载机制来帮助我们实现上述目的。
第四章 运算符重载
例:给出以下程序的运行结果。
#include <iostream.h> <iostream. int square(int x) { return x*x; x*x; } 此程序的运行结果为: double square(double y) The square of integer 7 is 49 { return y*y; y*y; The square of integer 7.5 is 56.25 } main() { cout<<” cout<<”The square of integer 7 is”<<square(7)<<endl; is”<<square(7)<<endl; cout<<” cout<<” The square of double 7.5 is”<<square(7.5)<<endl; is”<<square(7 )<<endl; return 0; }
函数重载
重载: 重载:
在同一作用域, 在同一作用域 , 允许多个函数使用同一名 字的措施。 字的措施。 名字相同, 参数个数或者 参数对应位置 名字相同 , 但 参数个数 或者参数对应位置 的类型不同,这样的函数称为重载 (overloading)。 overloading) 例如: int func(); func(); int func(int a,int b); b); void func(char *a,int b); b);
运算符重载
只听过数学中可以有运算, 对象之间也可以加减乘除???
运算符重载
C++语言允许程序员重新定义已有的运算符,使 C++语言允许程序员重新定义已有的运算符,使 其能按用户的要求完成一些特定的操作,这就是所谓 的运算符重载。运算符重载与函数重载相似,其目的 是设置某一运算符,让它具有另一种功能,尽管此运 算符在原先C++语言中代表另一种含义,但他们彼此 算符在原先C++语言中代表另一种含义,但他们彼此 之间并不冲突。C++会根据运算符的位置辨别应使用 之间并不冲突。C++会根据运算符的位置辨别应使用 哪一种功能进行运算。
简述运算符重载的规则。
简述运算符重载的规则。
篇一:运算符重载是C/C++语言中一种强大的功能,允许程序员自定义函数的行为,以处理不同类型的数据。
运算符重载允许程序员在函数中重载算术、逻辑和位运算符,从而能够处理数组、结构体和指针等不同类型的数据。
以下是运算符重载的规则:1. 算术运算符重载算术运算符包括加号、减号、乘号和除号。
每个算术运算符都有一组默认的行为,可以通过运算符重载来自定义它们的行为。
例如,重载加号运算符可以使函数接受一个整数参数,并返回一个新的整数。
下面是一个简单的例子,演示了如何重载加号运算符:```c++struct MyStruct {int value;};MyStruct operator+(const MyStruct& other, int value) {return MyStruct(value + other.value);}int main() {MyStruct mystruct1 = { 10 };MyStruct mystruct2 = { 20 };int result = mystruct1 + mystruct2;std::cout << "result = " << result << std::endl;return 0;}```在上面的例子中,我们定义了一个名为`MyStruct`的结构体类型,其中包含一个整数类型。
然后,我们定义了一个重载加号运算符的函数,该函数接受一个整数类型的参数,并返回一个新的`MyStruct`对象。
在`main`函数中,我们定义了两个`MyStruct`对象`mystruct1`和`mystruct2`,并将它们相加,结果存储在`result`变量中。
2. 逻辑运算符重载逻辑运算符包括条件运算符和逻辑非运算符。
每个逻辑运算符都有一组默认的行为,可以通过运算符重载来自定义它们的行为。
第四章运算符重载
2、对于任意一元运算符α:
(1)成员函数重载运算符
定义
type x::operator α( )
{…}
显式调用
objX.operator α( )
隐式调用
αobjX 或:ojbXα
(2)友元函数重载运算符
定义
type operator α(Xobj)
{…}
显式调用
operatorα(obj X)
隐式调用
友元函数重载运算符时,需要明确给出参数,不会出错。 3、不能用友元函数重载的运算符:
= 、 ( )、[]、- > 4、注意: (1)对THIS所指向的数据的任何改变都会影响到激活运算数函数的对象。 (2)可使用引用参数(指针)来解决重载时的二义性。
4.1.5 重载++和--
一、关于++和- 1、C中的++和- -的两种形式: 前缀:++i; 后缀:i--; 2、在C++中的约定 (显式地区分前缀和后缀) (1)对于前缀方式++i:
例4-1 1、重载“+”、“=”、“++”;读懂几个成员函数; 2、成员函数重载运算符,激活运算符的对象都是由THIS指针隐含传递的。
4.1.4 用友元函数重载运算符
1、成员函数重载可能造成的麻烦:成员函数重载的运算符不具有交换性。 原因:成员函数仅能被一个“实际对象”所调用,如果引起成员函数
调用的是一个值(非一个对象),成员函数将不能正确工作。 2、可用友元函数解决这一问题:
5、除“=”以外,重载的运算符可以被任何派生类所继承, “=”需要每个类明确定义自己的解释;
6、 重载可能让程序的可读性下降,在使用时应模仿运算符的 习惯用法 。
运算符重载——精选推荐
运算符重载运算符重载学习运算符重载,让运算符能做⼀些原来做不了的事情,⽅便它的使⽤⼀、运算符重载的概念1、什么是运算符重载1.重载:重新载⼊,就像之前学的函数重载,对⼀个已有的函数赋值⼀个新的定义,因此同⼀个函数名就可以有不同的含义。
2.运算符也是可以重载的,⽐如cout在输出⼀个变量的时候,能接受不同类型的数据并输出,他就是重载了<<运算符,这个就是运算符重载3.所以运算符重载指的是对已有的运算符重新定义新的运算规则,以适应不同的数据类型,当然重载之后之前的运算规则还是有的2、为什么要进⾏运算符重载1.运算符重载之后可以让运算符去适应不同的数据类型,对于基本数据类型,系统给出了运算符的操作规则,对于⾃定义数据类型来说,系统不知道该给出什么规则class student{int id;int age;char name[20];public:student(int id,int age,const char* name){this->id=id;this->age=age;strcpy(this->name,name);}}student stu1(1,23,"张三");student stu2(2,24,"李四");stu1+stu2;//如果是这样相加,那么应该加的是什么呢?编译器是不知道的,所以编译器就提供了运算符重载这个机制,让⽤户⾃定义运算符的运算规则⼆、运算符重载1、运算符重载类中定义1.关键字:operator,通过关键字来定义运算符重载(跟写个函数⼀样)2.定义:函数返回值类型 operator 要加载的运算符(参数列表){函数体;}这⾥把运算符的使⽤,理解为调⽤函数,只是和平时的调⽤函数有⼀点区别#include<iostream>#include<string>using namespace std;class student{int id;int age;string name;public:student(int age){this->age = age;id = 1;name = "sss ";}student(int id, int age, string name){this->id = id;this->age = age;this->name = name;}void showstudent(){cout << id << "\t" << age << "\t" << name << endl;}student operator+(student& p1)//这个函数会返回⼀个新的对象{int x=this->age + p1.age;student p(x);return p;//返回的是⼀个对象,会调⽤拷贝构造}int operator-(int x){return this->id - x;}void operator+(student&p2){cout << this->id + p2.id << endl;}};//1.操作这个运算符之后,返回值类型是什么int main(){student p1(0, 1, "yunfei");int x = p1.operator-(1);cout << x << endl;student stu1(1, 23, "张三");student stu2(2, 24, "李四");//student stu3 = stu1.operator+(stu2);//student stu3 = stu1 + stu2;stu1 + stu2;//stu3.showstudent();system("pause");return 0;}注意:因为我们这个运算符是在类中写的,所以是通过对象调⽤的,那么this指针会占⼀个参数,⽽且是第⼀个参数,也就是说我们重载⼀个运算符,是在类中,⽽这个运算符是个单⽬运算符,那么参数列表就不⽤写东西了,是双⽬运算符,那么就需要传另⼀个参数进来绝⼤部分的运算符重载都可以参照上⾯这个+号重载2、运算符重载的特点1.⼏乎所有的运算符都可以被重载,除了 . :: ()?() ) sizeof()2.运算符重载基本出现在类中和结构体中3.运算符可以理解为函数的⼀个表现3、运算符重载的注意事项1.重载运算符,这个重载的运算符还是满⾜原来的原则,但不能说重载+号,结果做的事-号的事,这样会使运算符的运⽤上增加很⼤的难度2.运算符重载的参数,类中重载调⽤对象会占⼀个参数,就是this会占⼀个参数,参数列表就是⽤来表⽰运算符的操作的3.对于运算符重载的调⽤,可以直接使⽤运算符,也可以通过对象 . 出来调⽤4.考虑返回值,不同的运算符有不同的返回值,要记得满⾜运算符原来的规则4、使⽤友元函数,实现运算符重载1.类在已经实现且部分修改的情况下下,需要进⾏运算符重载,就可以通过友元的⽅式来进⾏重载#include<iostream>#include<string>using namespace std;class person{int id;int age;string name;public:person(int id, int age, string name){this->id = id;this->age = age;this->name = name;}void showperson(){cout << id << "\t" << age << "\t" << name << endl;}friend int operator+(person&p1, person&p2);};//形参使⽤的是类对象的引⽤,在实参传对象的时候不会调⽤拷贝构造int operator+(person&p1, person&p2){return p1.id + p2.id;}//1.操作这个运算符之后,返回值类型是什么int main(){person stu1(1, 23, "张三");person stu2(2, 24, "李四");int x = operator+(stu1, stu2);//显⽰调⽤int y = stu1 + stu2;//隐式调⽤cout << x << endl << y << endl;system("pause");return 0;}容器:#include<iostream>#include<vector>using namespace std;int main(){//int 是v1这个容器存的类型vector<int> v1;for (int i = 0; i < 10; i++){//push_back()是⼀个函数,功能是尾插元素v1.push_back(i + 1);}for (int i = 0; i < 10; i++){cout << v1[i] << "\t";}system("pause");return 0;}左移右移运算符重载:#include<iostream>using namespace std;class person{int id;public:person(int id){this->id = id;}friend ostream& operator<<(ostream& os, person& p1);friend istream & operator>>(istream & in, person & p2);};//左移右移运算符重载,必须在类外重载,通过友元实现ostream& operator<<(ostream& os, person& p1)//左移运算符{os << p1.id << endl;return os;//返回的是⼀个cout,⽽且只能⽤引⽤}istream & operator>>(istream & in, person & p2)//右移运算符{in >> p2.id;return in;}int main(){person p1(10), p2(20);cin >> p1 >> p2;cout << p1 << endl << p2 << endl;system("pause");return 0;}前++,后++运算符重载:#include<iostream>using namespace std;class person{int id;public:person(int id){this->id = id;}person& operator++()//前++{this->id++;return *this;}person& operator++(int)//后++,int是⼀个占位符,⽤来区分前++和后++的{static person temp = *this;//引⽤不能返回局部变量,要⽤静态变量this->id++;return temp;}friend ostream& operator<<(ostream& os, person& p1);friend istream & operator>>(istream & in, person & p2);};//左移右移运算符重载,必须在类外重载,通过友元实现ostream& operator<<(ostream& os, person& p1)//左移运算符{os << p1.id << endl;return os;//返回的是⼀个cout,⽽且只能⽤引⽤}istream & operator>>(istream & in, person & p2)//右移运算符{in >> p2.id;return in;}int main(){person p1(10), p2(20);//cin >> p1 >> p2;//cout << p1 << endl << p2 << endl;cout << p1 ;//10cout << p1++ ;//10cout << p1 ;//11cout << ++p1 ;//12cout << p1 ;//12system("pause");return 0;}等号运算符重载:#include<iostream>using namespace std;class person{char* name;public:person(const char* name){this->name = new char[strlen(name) + 1];strcpy(this->name, name);}person& operator=(person&p1)//⽤不⽤引⽤传参,要看返回的对象会不会消失 {if (this->name != NULL){delete[]this->name;this->name = NULL;}this->name = new char[strlen() + 1];strcpy(this->name, );return *this;}void show(){cout << name << endl;}~person()//如果有申请函数,就要加上析构函数{if (name != NULL){delete[]name;name = NULL;}}};int main(){{person p1("张三"), p2("李四"), p3("王五");p1 = p2 = p3;p1.show();p2.show();p3.show();}//加上⼤括号,让对象死亡,就能调⽤析构函数system("pause");return 0;}智能指针和==号运算符重载:#include<iostream>using namespace std;class person{int id;public:person(int id){this->id = id;}void show(){cout << id << endl;}bool operator==(person& p){return this->id == p.id;}~person(){cout << "person的析构函数" << endl;}};class smartpointer{person* ps;//包含你要new出来的对象的类的指针public:smartpointer(person* p){ps = p;}//重载->person* operator->()//传回来的是地址,不是对象,不⽤引⽤{return ps;}//重载*person& operator*()//返回的是对象,会调⽤拷贝构造,所以⽤返回值⽤引⽤,就不会再调⽤拷贝构造了 {return *ps;//得到⼀个对象,}~smartpointer(){if (ps != NULL){delete ps;ps = NULL;}}};int main(){{smartpointer p(new person(5));p->show();(*p).show();person p1(1), p2(3);cout << (p1 == p2) << endl;}//有三个对象,所以析构函数执⾏了三次system("pause");return 0;}[]运算符重载:#include<iostream>using namespace std;class person{char* name;public:person(const char* name){this->name = new char[strlen(name) + 1];strcpy(this->name, name);}char& operator[](int index){return name[index];}~person(){if (name != NULL){delete[]name;name = NULL;}cout << "这是析构函数" << endl;}};int main(){person p("asdfg");cout << p[3] << endl;system("pause");return 0;}c++引⽤作为函数返回值:1.以引⽤返回函数值,定义函数时需要在函数名前加 &2.⽤引⽤返回⼀个函数值的最⼤好处是,在内存中不产⽣被返回值的副本3.返回值为引⽤的时候,返回的是⼀个地址,隐形指针4.当返回值不是引⽤时,编译器会专门给返回值分配出⼀块内存的引⽤作为返回值,必须遵守以下规则:(1)不能返回局部变量的引⽤。
C++程序设计04737 第4章 运算符重载
//成员函数
myComplex &operator=(double);
//成员函数 };
myComplex::myComplex(){ real=0;imag=0;}
myComplex::myComplex(double r,double i)
{real=r;imag=i;}
myComplex myComplex::addCom(myComplex c1) {return myComplex(this->real+c1.real,this->imag+c1.imag); } void myComplex::outCom(){cout<<"("<<real<<","<<imag<<")";} void myComplex::outCom(string s) {cout<<s<<"=("<<real<<","<<imag<<")"<<endl;} void myComplex::changeReal(double r) {this->real=r;} myComplex operator+(const myComplex &c1,const myComplex &c2) //c1+c2 {return myComplex(c1.real+c2.real,c1.imag+c2.imag);}//返回一个临时对象 myComplex operator+(const myComplex &c1,double r) //c1+r {return myComplex(c1.real+r,c1.imag);} //返回一个临时对象 myComplex operator+(double r,const myComplex &c1) //r+c1 {return myComplex(r+c1.real,c1.imag);} //返回一个临时对象 myComplex operator-(const myComplex &c1,const myComplex &c2)//c1-c2 {return myComplex(c1.real-c2.real,c1.imag-c2.imag);}//返回一个临时对象 myComplex operator-(const myComplex &c1,double r) //c1-r {return myComplex(c1.real-r,c1.imag);//返回一个临时对象} myComplex operator-(double r,const myComplex &c1) //r-c1 {return myComplex(r-c1.real,-c1.imag); //返回一个临时对象} myComplex &myComplex::operator=(const myComplex &c1) {this->real=c1.real;this->imag=c1.imag;return *this; } myComplex &myComplex::operator=(double r) {this->real=r;this->imag=0;return *this;}
运算符重载——精选推荐
运算符重载什么是运算符的重载?运算符与类结合,产⽣新的含义。
为什么要引⼊运算符重载?作⽤:为了实现类的多态性(多态是指⼀个函数名有多种含义)怎么实现运算符的重载?⽅式:类的成员函数或友元函数(类外的普通函数)规则:不能重载的运算符有 . 和 .* 和 ?: 和 :: 和 sizeof友元函数和成员函数的使⽤场合:⼀般情况下,建议⼀元运算符使⽤成员函数,⼆元运算符使⽤友元函数1、运算符的操作需要修改类对象的状态,则使⽤成员函数。
如需要做左值操作数的运算符(如=,+=,++)2、运算时,有数和对象的混合运算时,必须使⽤友元3、⼆元运算符中,第⼀个操作数为⾮对象时,必须使⽤友元函数。
如输⼊输出运算符<<和>>具体规则如下:运算符建议使⽤所有⼀元运算符成员函数= ( ) [ ] ->必须是成员函数+= -= /= *= ^= &= != %= >>= <<= , 似乎带等号的都在这⾥了成员函数所有其它⼆元运算符, 例如: –,+,*,/友元函数<< >>必须是友元函数2. 参数和返回值当参数不会被改变,⼀般按const引⽤来传递(若是使⽤成员函数重载,函数也为const).对于返回数值的决定:1) 如果返回值可能出现在=号左边, 则只能作为左值, 返回⾮const引⽤。
2) 如果返回值只能出现在=号右边, 则只需作为右值, 返回const型引⽤或者const型值。
3) 如果返回值既可能出现在=号左边或者右边, 则其返回值须作为左值, 返回⾮const引⽤。
运算符重载举例:+和 -运算符的重载:class Point{private:int x;public:Point(int x1){ x=x1;}Point(Point& p){ x=p.x;}const Point operator+(const Point& p);//使⽤成员函数重载加号运算符friend const Point operator-(const Point& p1,const Point& p2);//使⽤友元函数重载减号运算符};const Point Point::operator+(const Point& p){return Point(x+p.x);}Point const operator-(const Point& p1,const Point& p2){return Point(p1.x-p2.x);}输出:Point a(1);Point b(2);a+b; //正确,调⽤成员函数a-b; //正确,调⽤友元函数a+1; //正确,先调⽤类型转换函数,把1变成对象,之后调⽤成员函数a-1; //正确,先调⽤类型转换函数,把1变成对象,之后调⽤友元函数1+a; //错误,调⽤成员函数时,第⼀个操作数必须是对象,因为第⼀个操作数还有调⽤成员函数的功能1-a; //正确,先类型转换后调⽤友元函数总结:1、由于+ -都是出现在=号的右边,如c=a+b,即会返回⼀个右值,可以返回const型值2、后⼏个表达式讨论的就是,数和对象混合运算符的情况,⼀般出现这种情况,常使⽤友元函数3、双⽬运算符的重载:重载运算符函数名:operator@(参数表)隐式调⽤形式:obj1+obj2显式调⽤形式:obj1.operator+(OBJ obj2)---成员函数operator+(OBJ obj1,OBJ obj2)---友元函数执⾏时,隐式调⽤形式和显式调⽤形式都会调⽤函数operator+()++和--运算符的class Point{private:int x;public:Point(int x1){ x=x1;}Point operator++();//成员函数定义⾃增const Point operator++(int x); //后缀可以返回⼀个const类型的值friend Point operator--(Point& p);//友元函数定义--friend const Point operator--(Point& p,int x);//后缀可以返回⼀个const类型的值};Point Point::operator++()//++obj{x++;return *this;}const Point Point::operator++(int x)//obj++{Point temp = *this;this->x++;return temp; // 需要返回⼀个临时对象,效率不如 ++obj ⾼}Point operator--(Point& p)//--obj{p.x--;return p;//前缀形式(--obj)重载的时候没有虚参,通过引⽤返回*this 或⾃⾝引⽤,也就是返回变化之后的数值}const Point operator--(Point& p,int x)//obj--{Point temp = p;p.x--;return temp;// 后缀形式obj--重载的时候有⼀个int类型的虚参, 返回原状态的拷贝}调⽤:Point b(2);a++;//隐式调⽤成员函数operator++(0),后缀表达式++a;//隐式调⽤成员函数operator++(),前缀表达式b--;//隐式调⽤友元函数operator--(0),后缀表达式--b;//隐式调⽤友元函数operator--(),前缀表达式cout<<a.operator ++(2);//显式调⽤成员函数operator ++(2),后缀表达式cout<<a.operator ++();//显式调⽤成员函数operator ++(),前缀表达式cout<<operator --(b,2);//显式调⽤友元函数operator --(2),后缀表达式cout<<operator --(b);//显式调⽤友元函数operator --(),前缀表达式 </pre>总结:1、a++函数返回:temp(临时变量)函数返回是否是const类型:返回是⼀个拷贝后的临时变量),不能出现在等号的左边(临时变量不能做左值),函数的结果只能做右值,则要返回⼀个const类型的值++a函数返回:*this;函数返回是否是const类型:返回原状态的本⾝,返回值可以做左值,即函数的结果可以做左值,则要返回⼀个⾮const类型的值2、前后缀仅从函数名(operator++)⽆法区分,只能有参数区分,这⾥引⼊⼀个虚参数int x,x可以是任意整数。
运算符重载解读
02
在重载运算符时,应明确指定 运算符的参数类型和返回类型 ,避免与其他操作符混淆。
03
在重载运算符时,应尽量使用 有意义的操作符名称,以提高 代码的可读性。
考虑性能和效率
01
02
03
运算符重载时,应考虑 性能和效率,避免对原 有代码造成不必要的性
能损失。
在重载运算符时,应尽 量减少额外的计算和内 存开销,以提高代码的
一元运算符重载
一元运算符重载是指对一元运算符进行重载,使其能够应用于一个操作数。例如,在C中,我们可以 重载一元减号运算符(-)来返回一个数的相反数。
常见的一元运算符有:+、-、~、!等。
二元运算符重载
二元运算符重载是指对二元运算符进行重载,使其能够应用于两个操作数。例如,在C中,我们可以重载加号运算符(+)来定 义两个自定义类型的相加行为。
01
提高代码可读性
运算符重载可以使代码更易读, 因为运算符的使用可以使代码更 简洁、更直观。
02
03
方便函数调用
运算符重载可以使得函数调用更 加方便,因为运算符的使用可以 减少函数调用的开销。
04
缺点分析
易造成混淆
运算符重载可能会使得代码难以理解,因为 运算符的行为可能会被改变,导致读者难以
理解代码的含义。
常见的二元运算符有:+、-、*、/、%等。
三元运算符重载
三元运算符重载是指对三元运算符进行重载,使其能够应用于三个操作数。例如,在C中,我们可以重载条件运 算符(?)来定义一个自定义类型的条件判断行为。
常见的三元运算符有:?:。
03
运算符重载的常见场景
类与类之间的运算
01
两个类对象之间的加法运算,可以表示它们之间的某种关联或 合并。
运算符重载详解
运算符重载详解1.运算符重载定义:C++中预定义的运算符的操作对象只能是基本数据类型。
但实际上,对于许多⽤户⾃定义类型(例如类),也需要类似的运算操作。
这时就必须在C++中重新定义这些运算符,赋予已有运算符新的功能,使它能够⽤于特定类型执⾏特定的操作。
运算符重载的实质是函数重载,它提供了C++的可扩展性,也是C++最吸引⼈的特性之⼀。
运算符重载是通过创建运算符函数实现的,运算符函数定义了重载的运算符将要进⾏的操作。
运算符函数的定义与其他函数的定义类似,惟⼀的区别是运算符函数的函数名是由关键字operator和其后要重载的运算符符号构成的。
运算符函数定义的⼀般格式如下:<返回类型说明符> operator <运算符符号>(<参数表>){<函数体>} 2.运算符重载时要遵循以下规则:(1) 除了类属关系运算符"."、成员指针运算符".*"、作⽤域运算符"::"、sizeof运算符和三⽬运算符"?:"以外,C++中的所有运算符都可以重载。
(2) 重载运算符限制在C++语⾔中已有的运算符范围内的允许重载的运算符之中,不能创建新的运算符。
(3) 运算符重载实质上是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。
(4) 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符操作数的个数及语法结构。
(5) 运算符重载不能改变该运算符⽤于内部类型对象的含义。
它只能和⽤户⾃定义类型的对象⼀起使⽤,或者⽤于⽤户⾃定义类型的对象和内部类型的对象混合使⽤时。
(6) 运算符重载是针对新类型数据的实际需要对原有运算符进⾏的适当的改造,重载的功能应当与原有功能相类似,避免没有⽬的地使⽤重载运算符。
(7)重载运算符的函数不能有默认的参数,否则就改变了运算符的参数个数,与前⾯第3点相⽭盾了;(8)重载的运算符只能是⽤户⾃定义类型,否则就不是重载⽽是改变了现有的C++标准数据类型的运算符的规则了,会引会天下⼤乱的;(9)⽤户⾃定义类的运算符⼀般都必须重载后⽅可使⽤,但两个例外,运算符“=”和“&”不必⽤户重载;(10)运算符重载可以通过成员函数的形式,也可是通过友元函数,⾮成员⾮友元的普通函数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
4.1.6 重载赋值运算符
一、概述 1、“=”赋值运算符可以被重载; 赋值运算符可以被重载; 2、重载后不能被继承; 重载后不能被继承; 3、必须重载为成员函数。 必须重载为成员函数。 二、格式: 格式: X X :: operator=(const X from) { //复制X的成员; //复制 的成员; 复制X } 三、一般来说当缺省的类赋值函数不能正确工作时,考虑“=”的重载。 一般来说当缺省的类赋值函数不能正确工作时,考虑“ 的重载。
operatorα operatorα(objX) αobjX 或: objX α()
所需要的一个 操作数在参数 表中,由对象 显式地提供。
三、二元运算符 1、需要两个操作数; 需要两个操作数; 2、对于任意二元运算符β: 对于任意二元运算符β
方 式
定义
Type X::operator β(X obj) { … } Type operator β( X ojb) { … }
第四章
运算符重载
问题的提出
1、基本数据类型系统提供了大量运算符。 基本数据类型系统提供了大量运算符。 如:int x,y; x=x+y; 表达简洁,使用方便。 表达简洁,使用方便。 2、问题的提出: 问题的提出: 对于串类的对象合并: 对于串类的对象合并: string x, y; strcat(x,y);不如上述运算那样简单, strcat(x,y);不如上述运算那样简单,希望能改 不如上述运算那样简单 造为:x=x+y;更加简单和直观 更加简单和直观! 造为:x=x+y;更加简单和直观! 因此,需要对“+”进行不同的解释 进行不同的解释, 因此,需要对“+”进行不同的解释,即:重载
要重载的运算符 符号
2、运算符重载函数是友元函数 语法形式: 语法形式: Type operator@(参数表) operator@(参数表 参数表) { //相对于该类而定义的操作 //相对于该类而定义的操作 } 3、实例
…void operator++( ) void operator--( ) operator--( … void counter::operator++( ) { if (value<65535) value++; }
4.1.1 运算符重载的语法形式
一、通过运算符重载函数进行重载
1、运算符重载函数是成员函数 语法形式: 语法形式: Type X::operator@(参数表) X::operator@(参数表 参数表) { //相对于该类而定义的操作 //相对于该类而定义的操作 } 返回类型
重载该运算符的 类名
二、实例 Class X { … X operator ++() { a++; b++; return *this; } X operator ++(int x) { X temp; a++; b++; return temp; }
Class X { … friend operator ++(Y &a) { a.x++; b.y++; return a; } friend operator ++(Y &a, int i) { Y temp=a; a.x++; b.y++; return temp; }
4.1.4 用友元函数重载运算符
1、成员函数重载可能造成的麻烦:成员函数重载的运算符不具有交换性。 成员函数重载可能造成的麻烦:成员函数重载的运算符不具有交换性。 原因:成员函数仅能被一个“实际对象”所调用, 原因:成员函数仅能被一个“实际对象”所调用,如果引起成员函数 调用的是一个值(非一个对象) 成员函数将不能正确工作。 调用的是一个值(非一个对象),成员函数将不能正确工作。 2、可用友元函数解决这一问题: 可用友元函数解决这一问题: 友元函数重载运算符时,需要明确给出参数,不会出错。 友元函数重载运算符时,需要明确给出参数,不会出错。 3、不能用友元函数重载的运算符: 不能用友元函数重载的运算符: = 、 ( )、[]、- > )、[]、 、[]、注意: 4、注意: (1)对THIS所指向的数据的任何改变都会影响到激活运算数函数的对象 所指向的数据的任何改变都会影响到激活运算数函数的对象。 (1)对THIS所指向的数据的任何改变都会影响到激活运算数函数的对象。 (2)可使用引用参数 指针)来解决重载时的二义性。 可使用引用参数( (2)可使用引用参数(指针)来解决重载时的二义性。
4.1.5 重载++和-重载++和
一、关于++和- 关于++和 1、C中的++和- -的两种形式: 中的++和 的两种形式: 前缀:++i; 后缀: --; 前缀:++i; 后缀:i--; 2、在C++中的约定 (显式地区分前缀和后缀) C++中的约定 显式地区分前缀和后缀) (1)对于前缀方式++i: (1)对于前缀方式 对于前缀方式++i: 成员函数:XX::operator ++ (); 成员函数: 友元函数: 友元函数:X operator ++ (X&); (2)对于后缀方式 对于后缀方式i++: (2)对于后缀方式i++: 成员函数: 成员函数:XX::operator ++ (int); 友元函数: 友元函数:X operator ++(X&, int); 第二个参数INT一般设置为 第二个参数INT一般设置为0,如: 一般设置为0 i++ 等价于:i++(0) 或:i++=0 等价于:
4.1.2ቤተ መጻሕፍቲ ባይዱ一元和二元运算符
一、运算符重载函数定义的两种方式
1、成员函数和友元函数 2、差别的关键原因:this指针 差别的关键原因:this指针 二、一元运算符 1、不论前缀还是后缀,需要一个操作数 不论前缀还是后缀, 2、对于任意一元运算符α: 对于任意一元运算符α (1)成员函数重载运算符 (1)成员函数重载运算符 定义 type x::operator α( ) {…} 显式调用 objX.operator α( ) ojbXα 隐式调用 αobjX 或:ojbXα (2)友元函数重载运算符 (2)友元函数重载运算符 定义 type operator α(Xobj) {…} operatorα 显式调用 operatorα(obj X) 隐式调用 αojbX 或:objX α
objX1 β(objX2)
4.1.3 用成员函数重载运算符
例 4- 1 1、重载“+”、“=”、“++”;读懂几个成员函数; 重载“+”、 =”、 ++”;读懂几个成员函数; 2、成员函数重载运算符,激活运算符的对象都是由THIS指针隐含传递的。 成员函数重载运算符,激活运算符的对象都是由THIS指针隐含传递的 指针隐含传递的。
罗列运算符所 需要的操作数
… void counter::operator--( ) counter::operator--( { if (value>0) value--; value--; }
注意:重载中注意的问题 注意: 1、运算符重载函数是友元函数、成员函数的区别; 运算符重载函数是友元函数、成员函数的区别; 2、运算符被重载时,只是相对一特定类被重载,在特定的环 运算符被重载时,只是相对一特定类被重载, 境下作出特定的解释。当离开这个特定环境后, 境下作出特定的解释。当离开这个特定环境后,具有原来的 意义(系统定义) 意义(系统定义); 3、当重载运算符解释失败时,用该运算符的预定义版本(系统) 当重载运算符解释失败时,用该运算符的预定义版本(系统) 进行解释; 进行解释; 4、用此方法重载时,只能对一个系统已有运算符进行特定环 用此方法重载时, 境下的新的解释,而不能创造新的运算符。 境下的新的解释,而不能创造新的运算符。当运算符不够用 用函数调用来实现; 时,用函数调用来实现; 5、除“=”以外,重载的运算符可以被任何派生类所继承, =”以外 重载的运算符可以被任何派生类所继承, 以外, =”需要每个类明确定义自己的解释 需要每个类明确定义自己的解释; “=”需要每个类明确定义自己的解释; 6、 重载可能让程序的可读性下降,在使用时应模仿运算符的 重载可能让程序的可读性下降, 习惯用法 。
4.1 重载运算符
一、C++中的运算符 C++中的运算符
1、大多数系统预定义运算符都能重载,除开以下: 大多数系统预定义运算符都能重载,除开以下: . :: ?: # *(当乘法运算符时可重载 *(当乘法运算符时可重载) 当乘法运算符时可重载) “.” “::” “*”在C++中有特定定义 “*”在C++中有特定定义 ?:”不值得重载 “?:”不值得重载 “#”不能被重载 #”不能被重载 2、重载时的注意事项: 重载时的注意事项: (1)不能改变优先级; (1)不能改变优先级 不能改变优先级; (2)不能改变结合性; (2)不能改变结合性 不能改变结合性; (3)不能改变运算符所需操作数的个数; (3)不能改变运算符所需操作数的个数 不能改变运算符所需操作数的个数; (4)重载后,可按这些运算符的表达方式使用。 (4)重载后 可按这些运算符的表达方式使用。 重载后,
4.1.7 重载运算符()和[] 重载运算符()和
一、重载函数调用运算符() 重载函数调用运算符() 1、函数为:operator(); 函数为:operator(); 2、格式: 格式: X x; x(arg1, arg2) 可被解释为:x. operator ()(arg1,arg2); 可被解释为: ()(arg1,arg2); 二、重载下标运算符[] 重载下标运算符[] 1、函数为:operator[]; 函数为:operator[]; 2、格式: 格式: X x; x(y) 可被解释为:x. operator [ ](y); 可被解释为: ](y); 三、两都者只能采用成员函数重载,不能使用友元函数。 两都者只能采用成员函数重载,不能使用友元函数。