c++第4章运算符重载
c 运算符的重载习题答案
1.概念填空题1.1运算符重载是对已有的运算符赋予多重含义,使同一个运算符在作用于不同类型对象时导致不同的行为。
运算符重载的实质是函数重载,是类的多态性特征。
1.2可以定义一种特殊的类型转换函数,将类的对象转换成基本数据类型的数据。
但是这种类型转换函数只能定义为一个类的成员函数而不能定义为类的友元函数。
类类型转换函数既没有参数,也不显式给出返回类型。
类类型函数中必须有return 表达式的语句返回函数值。
一个类可以定义多个类类型转换函数。
1.3运算符重载时其函数名由operator运算符构成。
成员函数重载双目运算符时,左操作数是对象,右操作数是函数参数。
2.简答题2.2简述运算符重载的规则。
2.2简述重载单目运算符++、--,前置和后置时的差别。
2.3 C++中重运算符是否都可以重载?是否都可以重载成类的成员函数?是否都可以重载成类的友元函数?2.4 构造函数作为类型转换函数的条件是什么。
3.选择题3.1在下列运算符中,不能重载的是(B)A.!B. sizeofC. newD. delete3.2 不能用友员函数重载的是(A)。
A.=B.==C.<=D.++3.3下列函数中,不能重载运算符的函数是(B)。
A.成员函数B.构造函数C.普通函数D.友员函数3.4如果表达式++i*k时中的”++”和”*”都是重载的友元运算符,则采用运算符函数调用格式,该表达式还可表示为(B)。
A.operator*(i.operator++(),k) B.operator*(operator++(i),k)C.i.operator++().operator*(k) D.k.operator*(operator++(i))3.5已知在一个类体中包含如下函数原型:VOLUME operator-(VOLUME)const;下列关于这个函数的叙述中,错误的是(B )。
A.这是运算符-的重载运算符函数B.这个函数所重载的运算符是一个一元运算符C.这是一个成员函数D.这个函数不改变数据成员的值3.6在表达式x+y*z中,+是作为成员函数重载的运算符,*是作为非成员函数重载的运算符。
C程序设计运算符重载资料
• 在中只能重载单目运算符、双目运算符及不确定目数 运算符“()”
4.2.1 运算符重载为类的成员函数
• 通过该类的对象来调用运算符函数,由于对象本身将作为一 个操作数,因此要求第一个操作数的类型为用户自ቤተ መጻሕፍቲ ባይዱ义类, 参数表中的参数个数比操作数个数少一。
• 运算符重载的方法在实质上就是定义一个重载运算符 的函数,在执行被重载的运算符时,系统将调用此函 数实现相应的运算。运算符重载本质就是函数的重载。
• 重载运算符的函数的原型如下:
• 返回值类型运算符(形参表);
• 例如将“+”用于类的加法运算运算符重载的函数原 型可以为:
• ( 1, 2);
例4.2 通过运算符重载实现复数相加的示例。
例4.1 通过函数实现复数相加示例。 声明复数数
{
:
数据成员
;
实部
;
虚部
:
公有函数
( r = 0, i = 0): (r), (i){ } 构造函数
() ;
输出复数
( 1, 2);
复数加法
};
()
输出复数
{
( < 0) << << << "i" << ;
虚部为负
( 0) << << ;
虚部为0
<< << “+” << << “i” << ;
z1();
象的过程中调用输了出构z1造函数,语句将此临时对象作为函
第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++与面向对象程序设计第四章 运算符重载 (PPT4)
有:函数重载;
运算符重; 运算符重载——同一个运算符可以有多种含义或功能。
4.1 运算符重载的语法规则
函数返回值类型 operator 被重载的运算符(函数参数表)
说明:运算符进行重载本质——是编写运算符重载函数; 函数名——必须以operator开始,后跟被重载的运算符;
Байду номын сангаас
注意几点: 1.只能重载C++中已有的运算符。 2.“.”、“.*”、“::”、“?:”和sizeof这5个运算符不允许被 重载。除此之外,都可以被重载。 3.不能改变运算符的操作数个数。比如,对于单目运算符,它只能 有一个操作数。 4.不能改变运算符原有的优先级。 5.不能改变运算符原有的结合性。 6.不能改变运算符对C++内部那些预定义数据类型的操作方式。
C++与面向对象程序设计
第四章:运算符重载
本章教学内容
运算符重载的语法规则 复数类的运算符重载 (+) 字符串类的运算符重载 (+,=,[]) 运算符“<<”的重载 (复数,字符串对象输出 ) 类型转换函数(C++内部数据类型--->类对象)
第四章 运算符重载
“重载”技术是面向对象程序设计的主要特征之一。
//成员函数的实现CComplex.cpp CComplex::CComplex() //默认构造函数 { m_ Re =0.0; m_ Im =0.0; } CComplex::CComplex(double x,double y) //构造函数 { m_ Re=x; m_ Im=y; } CComplex CComplex::operator +(const CComplex c) //两个复数相加 { return CComplex (m_ Re + c.m_ Re, m_ Im+c.m_ Im); } CComplex CComplex::operator +(const double c) //一个复数加一个double数 { return CComplex ( m_ Re +c , m_ Im); }
第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; };
运算符重载(面向对象程序设计C++)
运算符重载运算符重载的本质是函数重载,它也是C++多态的一种体现,为用户提供了一个直观的接口,调用运算符操作自定义数据类型其实就是调用运算符函数。
运算符重载增强了C++的可扩充性,使得C++代码更加直观、易读,且便于对对象进行各种运算操作。
重载的运算符是具有特殊名字的函数:它们的名字由关键字operator 和其后要重载的运算符共同组成。
语法格式 返回类型 operator 运算符(参数列表){函数体; }运算符重载规则:只能重载C++中已有的运算符,不能创建新的运算符。
重载之后的运算符不能改变其优先级和结合性,也不能改变其操作数的个数及语法结构。
避免没有目的地使用重载运算符。
类属关系运算符“.”、成员指针运算符“*”、作用域运算符“::”、sizeof 运算符和三目运算符“?:”不可以重载。
输入输出运算符的重载 IO 标准库使用“>>”和“<<”运算符执行输入输出操作,对于这两个运算符来说,IO 库定义了其基本数据类型的操作,但若要直接对类对象进行输入输出,则需要在类中重载这两个运算符。
输入运算符语法格式istream& operator>>(istream&, 类对象引用);输出运算符语法格式ostream& operator<<(ostream&,const 类对象引用); 关系运算符的设计准则关系运算符都要成对的重载。
“==”运算符应该具有传递性当成对出现运算符重载时,可以把一个运算符的工作委托给另一个运算符。
赋值运算符的重载对于赋值运算符来说,如果不重载,那么类会自动为我们提供一个赋值运算符。
这个默认的赋值运算符跟默认拷贝构造函数一样,就是把一个对象的数据成员的值复制给另一个对象对应的数据成员。
下标运算符的重载返回类型 operator[] (参数列表);重载“[]”运算符可以实现两个目的:(1)“对象[下标]”的形式类似于“数组[下标]”,更加符合习惯。
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语言运算符的重载详解
C语⾔运算符的重载详解⽬录写⼀个Add函数为什么不⽤加号作为函数名运算符的重载上⾯问题解决总结写⼀个Add函数我们先讨论下⾯代码,并复习前⾯的内容class Complex{private:double Real, Image;public:Complex() :Real(0), Image(0) {}Complex(double r, double i) :Real(r), Image(i) {}~Complex() {}//Complex Add(const Complex* const this,const Complex &c)Complex Add(const Complex& x)const{Complex y;y.Real = Real + x.Real;y.Image = Image + x.Image;return y;//return Complex(this->Real + x.Real, this->Image + x.Image);}void Print(){cout << Real << "+" << Image << "i" << endl;}};int main(){Complex c1(12, 23);Complex c2(4.5, 5.6);Complex c3;c3 = c1.Add(c2);c3.Print();return 0;}直接return可以使⽤⽆名函数直接代替将亡值对象,相⽐可以省⼀次对象的构建我们再分析如果我们使⽤引⽤返回Add函数const Complex& Add(const Complex& x)const{Complex y;y.Real = Real + x.Real;y.Image = Image + x.Image;return y;//return Complex(this->Real + x.Real, this->Image + x.Image);}若我们以引⽤返回,将亡值对象会创建在Add函数的栈帧中,然后返回将亡值地址,函数return结束该空间会被释放、若没有引⽤,构建⽆名对象也就是将亡值对象会构建在主函数的空间中,这⾥使⽤将亡值对象值给到c3是没有问题的我们查看对象的构造与析构class Complex{private:double Real, Image;public:Complex() :Real(0), Image(0) {}Complex(double r, double i) :Real(r), Image(i){cout << "Create:" << this << endl;}Complex(const Complex& x):Real(x.Real),Image(x.Image){cout << "Copy Create:" << this << endl;}~Complex(){cout << "~Complex:" << this << endl;}//Complex Add(const Complex* const this,const Complex &c)Complex Add(const Complex& x)const{return Complex(this->Real + x.Real, this->Image + x.Image);}void Print(){cout << Real << "+" << Image << "i" << endl;}};int main(){Complex c1(12, 23);Complex c2(4.5, 5.6);Complex c3;c3 = c1.Add(c2);c3.Print();return 0;}⾸先我们使⽤引⽤返回需要加上const修饰,这是因为我们返回将亡值在临时空间具有常性,所以普通引⽤是不能进⾏返回的,需要使⽤常引⽤返回const Complex& Add(const Complex& x)const{return Complex(this->Real + x.Real, this->Image + x.Image);}我们发现对临时对象的构建后马上就进⾏析构,那么是怎么将数据拿出给到c3的?这个在最后我们进⾏分析为什么不⽤加号作为函数名//Complex operator+(const Complex* const this,const Complex &c)Complex operator+(const Complex &c) const{return Complex(this->Real + x.Real, this->Image + x.Image);}这⾥是不可以的,加号是⼀个操作符,不能使⽤操作放作为有效的函数名称;但是在C++中为了使这些操作符号能够当作函数名,那么我们需要在前⾯加上⼀个关键字operator//Complex operator+(const Complex* const this,const Complex &c)Complex operator+(const Complex &c) const{return Complex(this->Real + x.Real, this->Image + x.Image);}也就是告诉编译器,加号是⼀个有效的函数名,这就叫做运算符的重载;随后我们之间使⽤ c3 = c1 + c2 就是可以的int main(){Complex c1(12, 23);Complex c2(4.5, 5.6);Complex c3;c3 = c1 + c2;//编译器编译会是下⾯的情况//c3 = c1.operator+(c2);//c3 = operator+(&c1,c2); 加上this指针}运算符的重载⼀个对象,编译器会给它有6个缺省函数我们再来看下⾯这个问题//我们写⼀个赋值运算符重载void operator=(const Object& obj){this->value = obj.value;}//返回类型为void,这样不可以就不可以连等//obja = objb = objc;//obja = objb.operator=(objc);//obja = operator=(&objb,objc); 返回的⽆类型,不能给obja赋值且赋值函数不可以定义为const修饰Object& operator=(const Object& obj){this->value = obj.value;return *this;}obja = objb = objc;//改写obja = objb.operator=(objc);obja = operator=(&objb,objc);obja.operator=(operator=(&objb,objc));operator=(&obja,operator=(&objb,objc));通过返回对象,就可以实现连等;并且我们可以通过引⽤返回,因为此对象的⽣存期并不受函数的影响,不会产⽣⼀个临时对象作为⼀个过度防⽌⾃赋值若是我们将obja给obja赋值,也就是⾃赋值obja = objaoperator=(&obja,obja);我们就需要进⾏⼀步判断Object& operator=(const Object& obj){if(this != &obj)//防⽌⾃赋值{this->value = obj.value;}return *this;}上⾯问题解决我们通过这段代码来看,与上⾯问题相同Object& operator=(const Object& obj){if (this != &obj){this->value = obj.value;}return *this;}};Object& fun(const Object& obj){int val = obj.Value() + 10;Object obja(val);return obja;}int main(){Object objx(0);Object objy(0);objy = fun(objx);cout << objy.Value() << endl;return 0;}我们在这⾥希望通过引⽤返回,这⾥return的临时对象会构建在fun函数的栈帧中,并且在函数结束栈帧释放,随后调⽤赋值运算符重载,但是数值依旧是正确的我们跟踪这个被析构对象的地址,⾸先我们定位在fun函数的return obja;,随后进⼊析构函数将我们的obja进⾏析构接着运⾏到回到主函数进⾏赋值,接着进⼊赋值运算符重载,可以看到,这⾥的obj地址与已被析构的obja地址相同可以看到这个值依旧存在,依旧可以打印给出,这是因为vs2019的特殊性质造成的;我们每次运⾏程序会发现每次的对象地址都在变化,逻辑地址会随机改变,被析构对象的栈帧不会被接下来的赋值运算符重载扰乱地址空间,所以即使我们引⽤返回的对象已经死亡依旧可以将数值正确返回但是在vc中,我们得到的值会是随机值,这是因为vc中每次运⾏程序地址都不会改变,当我们从fun函数退出进⼊赋值语句中,就会将原本存储数据的地址扰乱,继⽽变成了随机值尽管我们引⽤返回能够将数据正确打印,但是该对象已经死亡,这是不安全的,所以我们⼀定不要以引⽤返回对象VS2019具有⼀个特点:当我们调⽤函数,若函数中没有定义局部变量或局部对象时,该函数基本不对栈帧进⾏清扫总结到此这篇关于C语⾔运算符的重载详解的⽂章就介绍到这了,更多相关C语⾔运算符重载内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
第四章 运算符重载
4.3重载运算符的规则
(1)C++只允许已有的部分运算符实施重载。 (2)不能重载的运算符有五个。 (3)重载不改变操作数的个数。 (4)重载不改变运算符的优先级。 (5)运算符重载函数不能带默认值参数。 (6)运算符重载函数必须与自定义类型的对象联 合使用,其参数至少有一个类对象或类对象引用。 (7)C++默认提供 = 和 & 运算符重载。
例4.1 通过成员函数实现复数的加法。 class Complex { private: double real; double imag; public: Complex(){real=0;imag=0;} Complex(double r,double i){real=r;imag=i;} Complex complex_add(Complex &c2); void display(); };
int main() {Complex c1(3,4),c2(5,-10),c3; c3=c1+c2; cout<<"c1=";c1.display(); cout<<"c2=";c2.display(); cout<<"c1+c2=";c3.display(); return 0; }
说明: (1)用运算符重载函数取代了例 4.1中的加法成 员函数,从外观上看函数体和函数返回值都是相 同的。 (2)在主函数中的表达式c3=c2+c1 取代了例4.1 中的c3=plex_add(c2) ,编译系统将表达 式c3=c1+c2 解释为 c1.operator + ( c2 ) 对象c1调用的重载函数operator + ,以c2为实参 计算两个复数之和。
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)不能返回局部变量的引⽤。
ch4(2)运算符重载
C++语言程序设计
Ch4.3 函数重载小结
函数重载的两种情况: 一是普通函数(类外的全局函数)重载; 二是同一个类中的成员函数的重载。
[读例题P155 4.9 找出重载的成员函数。]
5
C++语言程序设计
Ch4.4 运算符重载
// 引入问题:——复数的运算 class complex //复数类声明 { public: complex(double r=0.0,double i=0.0) //构造函数 { real=r; imag=i; } void display( ){cout<<"("<<real<<","<<imag<<")"<<endl; } //显示复数的值 private: double real; double imag; };
例1 在复数类中重载+ - 运算符
问题:将“+”、“-”运算重载为复数类的 成员函数。
复数运算规则:
– 加法: (a+bi)+(c+di)=(a+c)+(b+d)i
– 减法:(a+bi)-(c+di)=(a-c)+(b-d)i
– 操作数:两个操作数都是复数类的对象。
12
#include<iostream> using namespace std; class complex //复数类声明 { public: //外部接口 complex(double r=0.0,double i=0.0) {real=r; imag=i;} //构造函数 complex operator + (complex c2); //+重载为成员函数 complex operator - (complex c2); //-重载为成员函数 void display(); //输出复数 private: //私有数据成员 double real; //复数实部 double imag; //复数虚部 };
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;}
运算符重载解读
02
在重载运算符时,应明确指定 运算符的参数类型和返回类型 ,避免与其他操作符混淆。
03
在重载运算符时,应尽量使用 有意义的操作符名称,以提高 代码的可读性。
考虑性能和效率
01
02
03
运算符重载时,应考虑 性能和效率,避免对原 有代码造成不必要的性
能损失。
在重载运算符时,应尽 量减少额外的计算和内 存开销,以提高代码的
一元运算符重载
一元运算符重载是指对一元运算符进行重载,使其能够应用于一个操作数。例如,在C中,我们可以 重载一元减号运算符(-)来返回一个数的相反数。
常见的一元运算符有:+、-、~、!等。
二元运算符重载
二元运算符重载是指对二元运算符进行重载,使其能够应用于两个操作数。例如,在C中,我们可以重载加号运算符(+)来定 义两个自定义类型的相加行为。
01
提高代码可读性
运算符重载可以使代码更易读, 因为运算符的使用可以使代码更 简洁、更直观。
02
03
方便函数调用
运算符重载可以使得函数调用更 加方便,因为运算符的使用可以 减少函数调用的开销。
04
缺点分析
易造成混淆
运算符重载可能会使得代码难以理解,因为 运算符的行为可能会被改变,导致读者难以
理解代码的含义。
常见的二元运算符有:+、-、*、/、%等。
三元运算符重载
三元运算符重载是指对三元运算符进行重载,使其能够应用于三个操作数。例如,在C中,我们可以重载条件运 算符(?)来定义一个自定义类型的条件判断行为。
常见的三元运算符有:?:。
03
运算符重载的常见场景
类与类之间的运算
01
两个类对象之间的加法运算,可以表示它们之间的某种关联或 合并。
C++第4章 运算符重载
• • • •
一些特殊操作符的重载
4.4.1 重载++与--运算符 4.4.2 重载赋值运算符 4.4.3 重载[ ]和()运算符 4.4.4 重载插入( <<)和提取( >>)运 算符
14
4.4.1 重载++与--运算符
1.重载为类的成员函数 • 增量运算符++和减量运算符--都是一元运算符, 它们只有一个操作数。另外,增量运算符和减 量运算符可以用于前缀或后缀运算形式。
18
4.4.1 重载++与--运算符
2. 重载为类的友元函数 • 一元运算符重载为类的成员函数时,一般不需 要显示说明参数。因为重载为类的成员函数, 总是隐藏了一个参数,该参数是this指针。当 重载为类的友元函数时,由于不存在隐含的 this指针,对一元运算符来说,友元函数必须 有一个参数。
19
4.4.1 重载++与--运算符
CPoint operator++(CPoint &e){ return CPoint (++e. x, ++e. y); } CPoint operator++(CPoint &e,int){ return CPoint (e.x++,e.y++); } void main(){ CPoint p1(10,10),p2; p2=p1++; p1.display(); p2.display(); p2=++p1; p1.display(); p2.display(); }
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++面向对象程序设计
运 算 符 重 载
例4.3
将+、-(双目)重载为复数类的友元 函数。 两个操作数都是复数类的对象。
中国石油大学(北京)
26
#include<iostream> using namespace std; class complex //复数类声明 { public: //外部接口 complex(double r=0.0,double i=0.0) { real=r; imag=i; } //构造函数 friend complex operator + (complex c1,complex c2); //运 算符+重载为友元函数 friend complex operator - (complex c1,complex c2); //运 算符-重载为友元函数 void display(); //显示复数的值 private: //私有数据成员 double real; double imag; };
中国石油大学(北京) 3
C++面向对象程序设计
运 算 符 重 载
问题举例——复数的运算
用“+”、“-”能够实现复数的加减 运算吗? 实现复数加减运算的方法 ——重载“+”、“-”运算符
中国石油大学(北京)
4
C++面向对象程序设计
运 算 符 重 载
运算符重载的实质
运算符重载是对已有的运算符赋予多重含义 必要性
C++面向对象程序设计
什么是运算符重载
函数重载:一名多用
– 语法规则?
“<<”、“>>”:C++位移运算符重载为 流插入和流提取运算符 运算符重载:对C++运算符的功能进 行重载
中国石油大学(北京)
2
C++面向对象程序设计
运 算 符 重 载
问题举例——复数的运算
class complex //复数类声明 { public: complex(double r=0.0,double i=0.0) //构造函数 { real=r; imag=i; } void display(); //显示复数的值 private: double real; double imag; };
13
void complex::display() { cout<<"("<<real<<","<<imag<<")"<<endl; } void main() //主函数 { complex c1(5,4),c2(2,10),c3; //声明复数类的对象 cout<<"c1="; c1.display(); cout<<"c2="; c2.display(); c3=c1-c2; //使用重载运算符完成复数减法 cout<<"c3=c1-c2="; c3.display(); c3=c1+c2; //使用重载运算符完成复数加法 cout<<"c3=c1+c2="; c3.display(); }
22
程序运行结果为: First time output: 23:59:59 Show myClock++: 23:59:59 Show ++myClock: 0:0:1
23
C++面向对象程序设计
运 算 符 重 载
运算符友元函数的设计
如果需要重载一个运算符,使之能够 用于操作某类对象的私有成员,可以 此将运算符重载为该类的友元函数。 函数的形参代表依自左至右次序排列 的各操作数。 后置单目运算符 ++和--的重载函数, 形参列表中要增加一个int,但不必写 形参名。
中国石油大学(北京) 24
C++面向对象程序设计
运 算 符 重 载
运算符友元函数的设计
双目运算符 B重载后, 表达式oprd1 B oprd2 等同于operator B(oprd1,oprd2 ) 前置单目运算符 B重载后, 表达式 B oprd 等同于operator B(oprd ) 后置单目运算符 ++和--重载后, 表达式 oprd B 等同于operator B(oprd,0 )
中国石油大学(北京) 9
C++面向对象程序设计
运 算 符 重 载
例 4.1
将“+”、“-”运算重载为复数类 的成员函数。 规则:
– 实部和虚部分别相加减。
操作数:
– 两个操作数都是复数类的对象。
中国石油大学(北京)
10
#include<iostream> using namespace std; class complex //复数类声明 { public: //外部接口 complex(double r=0.0,double i=0.0){real=r;imag=i;} //构造函数 complex operator + (complex c2); //+重载为成员函数 complex operator - (complex c2); //-重载为成员函数 void display(); //输出复数 private: //私有数据成员 double real; //复数实部 double imag; //复数虚部 };
19
Clock& Clock::operator ++() { Second++; if(Second>=60) { Second=Second-60; Minute++; if(Minute>=60) { Minute=Minute-60; Hour++; Hour=Hour%24; } } return *this; }
//运算符重
return complex(c2.real+c1.real, c2.imag+c1.imag); //运算符重
28
C++面向对象程序设计
运算符重载原则
双目运算符通常重载为类的友员函数
– 为了符合交换率等
单目运算符通常重载为类的成员函数
– 方便、简单
中国石油大学(北京)
29
C++面向对象程序设计
重载“<<“和“>>“运算符
C++标准类库中提供:
– – 输入流类istream, cin是该类型的对象 输出流类ostream, cout是该类型的对象
“<<“和“>>“用来输入输出标准类型的数据 重载形式
istream & operator >> (istream &, 自定义类 &); ostream & operator << (ostream &, 自定义类 &);
规则和限制
可以重载C++中除下列运算符外的所 有运算符: . .* :: ?: sizeof 只能重载C++语言中已有的运算符, 不可臆造新的。 不改变原运算符的优先级和结合性。 不能改变操作数个数。 经重载的运算符,其操作数中至少应 该有一个是自定义类型。?
中国石油大学(北京) 6
C++面向对象程序设计
14
程序输出的结果为: c1=(5,4) c2=(2,10) c3=c1-c2=(3,-6) c3=c1+c2=(7,14) 将调用几次构造函数?
15
C++面向对象程序设计
运 算 符 重 载
运算符成员函数的设计
前置单目运算符 U
– 如果要重载 U 为类成员函数,使之能够 实现表达式 U oprd,其中 oprd 为A类对 象,则 U 应被重载为 A 类的成员函数, 无形参。 – 经重载后, 表达式 U oprd 相当于 oprd.operator U()
中国石油大学(北京) 8
C++面向对象程序设计
运 算 符 重 载
运算符成员函数的设计
双目运算符 B
– 如果要重载 B 为类成员函数,使之能够实 现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函 数,形参类型应该是 oprd2 所属的类型。 – 经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2)
//前置单目运算符重载函数
20
//后置单目运算符重载 Clock Clock::operator ++(int) { //注意形参表中的整型参数 Clock old=*this; ++(*this); return old; }
21
//其它成员函数的实现略 void main() { Clock myClock(23,59,59); cout<<"First time output:"; myClock.ShowTime(); cout<<"Show myClock++:"; (myClock++).ShowTime(); cout<<"Show ++myClock:"; (++myClock).ShowTime(); }
C++面向对象程序设计