实验十六运算符重载解读
- 格式:doc
- 大小:23.50 KB
- 文档页数:2
运算符重载实验报告运算符重载实验报告引言:运算符重载是C++语言中的一项重要特性,它允许用户自定义运算符的行为。
通过运算符重载,可以使得程序更加直观、简洁,并提高代码的可读性和可维护性。
本实验旨在探索运算符重载的用法和效果。
一、实验目的本实验旨在通过实际操作,深入了解运算符重载的机制和使用方法,以及运算符重载对程序设计的影响。
二、实验环境本实验使用C++编程语言,并在Visual Studio开发环境下进行实验。
三、实验过程1. 了解运算符重载的基本概念运算符重载是指通过定义函数,改变运算符的行为。
在C++中,可以通过重载运算符函数来实现运算符的重载。
运算符重载函数的命名规则为"operator 运算符",例如"operator+"表示重载加法运算符。
2. 实现运算符重载的实验示例为了更好地理解运算符重载的使用方法,我们以矩阵的加法为例进行实验。
首先,定义一个Matrix类,并重载"+"运算符。
```cppclass Matrix {private:int** data;int rows;int cols;public:Matrix(int rows, int cols) {this->rows = rows;this->cols = cols;data = new int*[rows];for (int i = 0; i < rows; ++i) {data[i] = new int[cols];}}Matrix operator+(const Matrix& other) {Matrix result(rows, cols);for (int i = 0; i < rows; ++i) {for (int j = 0; j < cols; ++j) {result.data[i][j] = data[i][j] + other.data[i][j]; }}return result;}};```在上述代码中,我们定义了一个Matrix类,其中包含矩阵的数据成员data、行数rows和列数cols。
C++基础知识之运算符重载详解⽬录运算符重载⽅式⼀, 使⽤成员函数重载运算符需求:把⽜⾁换猪⾁, ⽺⾁换猪⾁⽅式⼆, 使⽤⾮成员函数【友元函数】重载运算符两种⽅式的区别两种⽅式的选择:总结运算符重载为什么要使⽤运算符重载-C/C++的运算符,⽀持的数据类型,仅限于基本数据类型。
问题:⼀头⽜+⼀头马 = ?(⽜马神兽?)⼀个圆 +⼀个圆 = ?(想要变成⼀个更⼤的圆)⼀头⽜ – ⼀只⽺ = ? (想要变成4只⽺,原始的以物易物:1头⽜价值5只⽺)解决⽅案:使⽤运算符重载⽅式⼀, 使⽤成员函数重载运算符需求:把⽜⾁换猪⾁, ⽺⾁换猪⾁规则:⼀⽄⽜⾁:2⽄猪⾁⼀⽄⽺⾁:3⽄猪⾁实现:⽜ + ⽜ = ?猪⾁⽜ + ⽺ = ?猪⾁Cow类> Cow.h#pragma onceclass Pork;class Sheep;class Cow{ //⽜类public:Cow(int weight = 0);//使⽤运算符重载, 实现⽜⾁ + ⽜⾁ = 猪⾁Pork operator+(const Cow& cow);//使⽤运算符重载, 实现⽜⾁ + ⽺⾁ = 猪⾁Pork operator+(const Sheep& sheep);private:int weight; //重量};_________________________________________________________________________________________________________________________________ > Cow.cpp#include "Cow.h"#include "Pork.h"#include "Sheep.h"Cow::Cow(int weight){this->weight = weight;}//⼀⽄⽜⾁换两⽄猪⾁Pork Cow::operator+(const Cow& cow){return Pork((this->weight + cow.weight) * 2);}//⼀⽄⽜⾁换两⽄猪⾁, ⼀⽄⽺⾁换三⽄猪⾁Pork Cow::operator+(const Sheep& sheep){int tmp = (this->weight * 2) + (sheep.getWeight() * 3);return Pork(tmp);}Sheep类> Sheep.h#pragma once//⽺类class Sheep{public:Sheep(int weight = 0);int getWeight() const;private:int weight; //重量};_________________________________________________________________________________________________________________________________ > Sheep.cpp#include "Sheep.h"Sheep::Sheep(int weight){this->weight = weight;}int Sheep::getWeight() const{return weight;}Pork类> Pork.h#pragma once#include <string>using namespace std;class Pork{ //猪⾁类public:Pork(int weight = 0);string description() const;private:int weight;};_________________________________________________________________________________________________________________________________ > Pork.cpp#include <sstream>#include "Pork.h"Pork::Pork(int weight){this->weight = weight;}string Pork::description() const{stringstream ret;ret << this->weight << "⽄";return ret.str();}main.cpp#include <iostream>#include <Windows.h>#include "Cow.h"#include "Pork.h"#include "Sheep.h"using namespace std;int main(void) {Pork p1;Cow c1(100);Cow c2(200);Sheep s1(100);//调⽤运算符重载 Pork operator+(const Cow& cow);p1 = c1 + c2;cout << "⽜ + ⽜ = 猪⾁:" << p1.description() << endl;//调⽤运算符重载 Pork operator+(const Sheep& c1);p1 = c1 + s1;cout << "⽜ + ⽺ = 猪⾁:" << p1.description() << endl;//⽺+⽜会报错, 因为没有定义对应的⽺+⽜运算符重载//p1 = s1 + c1;system("pause");return 0;}⽅式⼆, 使⽤⾮成员函数【友元函数】重载运算符实现:⽜ + ⽜ = ?猪⾁⽜ + ⽺ = ?猪⾁Cow类> Cow.h#pragma onceclass Pork;class Sheep;class Cow{ //⽜类public:Cow(int weight = 0);//使⽤友元运算符重载, 实现⽜⾁ + ⽜⾁ = 猪⾁friend Pork operator+(const Cow& c1, const Cow& c2);//使⽤友元运算符重载, 实现⽜⾁ + ⽺⾁ = 猪⾁friend Pork operator+(const Cow& c1, const Sheep& s1);private:int weight; //重量};_________________________________________________________________________________________________________________________________ > Cow.cpp#include "Cow.h"Cow::Cow(int weight){this->weight = weight;}Sheep类> Sheep.h#pragma once//⽺类class Sheep{public:Sheep(int weight = 0);int getWeight() const;private:int weight; //重量};_________________________________________________________________________________________________________________________________ > Sheep.cpp#include "Sheep.h"Sheep::Sheep(int weight){this->weight = weight;}int Sheep::getWeight() const{return weight;}Pork类> Pork.h#pragma once#include <string>using namespace std;class Pork{ //猪⾁类public:Pork(int weight = 0);string description() const;private:int weight;};_________________________________________________________________________________________________________________________________ > Pork.cpp#include <sstream>#include "Pork.h"Pork::Pork(int weight){this->weight = weight;}string Pork::description() const{stringstream ret;ret << this->weight << "⽄";return ret.str();}main.cpp#include <iostream>#include <Windows.h>#include "Cow.h"#include "Pork.h"#include "Sheep.h"using namespace std;//要想访问类的私有数据成员, 就把这个函数定义为友元Pork operator+(const Cow& c1, const Cow& c2) {return ((c1.weight + c2.weight) * 2);}//要想访问类的私有数据成员, 就把这个函数定义为友元Pork operator+(const Cow& c1, const Sheep& s1) {return((c1.weight * 2) + (s1.getWeight() * 3));}int main(void) {Pork p1;Cow c1(100); //100⽄的⽜Cow c2(200); //200⽄的⽜Sheep s1(100); //100⽄的⽺//调⽤ friend Pork operator+(const Cow& c1, const Cow& c2);p1 = c1 + c2;cout << "使⽤友元⽜ + ⽜ = 猪⾁:" << p1.description() << endl;//调⽤ friend Pork operator+(const Cow& c1, const Sheep& s1);p1 = c1 + s1;cout << "使⽤友元⽜ + ⽺ = 猪⾁:" << p1.description() << endl;system("pause");return 0;}两种⽅式的区别区别:使⽤成员函数来实现运算符重载时,少写⼀个参数,因为第⼀个参数就是this指针。
1、多态性的基本概念2、派生类对象替换基类对象3、虚函数的定义4、抽象类的定义5、宠物类的设计6、运算符重载7、日期类对象判断大小8、分数类对象运算符重载☐运算符重载指赋予运算符新的操作功能,主要用于对类的对象的操作☐运算符+意味着多少对象类型的加法呢?☐还可以定义新的对象类型加法☐运算符重载定义形式:<类型><类名>::operator<操作符>(<参数表>){函数体}☐首先定义虚数类☐虚数可以描述为:a+bi☐a与b看成实数,定义成double类型☐成员函数除了构造与析构外,还有:☐输出虚数、修改虚数、得到实部a、得到虚部b ☐相加+、判相等==#include <iostream>using namespace std;class Complex{private:double real, imag;public:Complex(double r = 0, double i = 0): real(r), imag(i){ }double Real(){return real;}double Imag(){return imag;}Complex operator +(Complex&);Complex operator +(double);bool operator ==(Complex);~Complex(){ };Complex Complex::operator +(Complex &c)// 重载运算符+,两边是虚数对象{Complex temp;temp.real = real+c.real;temp.imag = imag+c.imag;return temp;}Complex Complex::operator +(double d)// 重载运算符+,左边是虚数对象,右边是双精度数{Complex temp;temp.real = real+d;temp.imag=imag;return temp;}bool Complex::operator ==(Complex c)// 重载运算符=={if (real == c.real && imag == c.imag)return true;elseint main(){Complex c1(3,4),c2(5,6),c3;cout << "C1 = " << c1.Real() << "+j" << c1.Imag() << endl;cout << "C2 = " << c2.Real() << "+j" << c2.Imag() << endl;c3 = c1+c2;cout << "C3 = " << c3.Real() << "+j" << c3.Imag() << endl;c3 = c3+6.5;cout << "C3 + 6.5 = " << c3.Real() << "+j" << c3.Imag() << endl;if ( c1==c2 )cout<<“两个复数相等”;elsecout<<“两个复数不相等”;return 0;☐运算符++分前置运算符和后置运算符☐例如: ++Y与Y++☐前置运算符定义Complex Complex::operator ++ () {real+=1;return *this;}☐后置运算符定义Complex Complex::operator ++ (int) {real+=1;return *this;}。
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语⾔运算符重载内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
一、实验目的1. 理解运算符重载的概念和原理。
2. 掌握C++中运算符重载的方法和规则。
3. 通过实例,实现自定义类型对运算符的重载。
4. 分析运算符重载在实际编程中的应用和优势。
二、实验环境1. 编程语言:C++2. 开发环境:Visual Studio 20193. 操作系统:Windows 10三、实验内容1. 运算符重载的概念和原理2. 运算符重载的方法和规则3. 自定义类型运算符重载实例4. 运算符重载的实际应用四、实验步骤1. 概念和原理运算符重载是指为已有的运算符赋予新的功能,使其能够应用于自定义类型的数据。
在C++中,运算符重载可以通过成员函数或友元函数实现。
2. 方法和规则- 成员函数重载:在自定义类型中定义一个成员函数,该函数的名称与要重载的运算符相同。
- 友元函数重载:在自定义类型外部定义一个友元函数,该函数的名称与要重载的运算符相同,并在函数声明中添加类名和作用域解析运算符。
运算符重载规则:- 运算符重载的函数必须返回与操作数相同的类型。
- 运算符重载的函数不能改变原有运算符的操作数个数。
- 运算符重载的函数不能改变原有运算符的优先级。
- 运算符重载的函数不能改变原有运算符的结合性。
3. 自定义类型运算符重载实例假设我们有一个自定义类型`Point`,表示二维平面上的一个点,其坐标为`(x, y)`。
```cppclass Point {public:int x, y;Point(int x, int y) : x(x), y(y) {}// 成员函数重载加法运算符Point operator+(const Point& p) const {return Point(x + p.x, y + p.y);}// 友元函数重载加法运算符friend Point operator-(const Point& p1, const Point& p2);};// 实现友元函数重载减法运算符Point operator-(const Point& p1, const Point& p2) {return Point(p1.x - p2.x, p1.y - p2.y);}```4. 运算符重载的实际应用运算符重载在实际编程中具有以下优势:- 提高代码可读性:使用自定义类型时,可以像操作基本数据类型一样使用运算符,提高代码的可读性。
实验十六运算符重载
一、实验目的
1、理解运算符重载作用和意义;
2、掌握类运算符和友元运算符重载的定义和使用;
3、掌握常用运算符(++、--、+、-、*、/、=、+=、-=、*=、/=、<<(插入)、>>(提取))的重载。
二、实验内容
1、下列程序定义了一个复数类,重载"+"运算符以实现复数的加法运算。
#include<iostream.h>
class Complex{
float Real,Image; //复数的实部和虚部
public:
Complex(float r=0,float i=0) //初始化对象
{ Real=r,Image=i; }
float& AccessR() //存取实部
{ return Real; }
float& AccessI() //存取虚部
{ return Image; }
void Show() //显示复数
{ cout<<Real;
if(Image>=0) cout<<"\t+"; else cout<<"\t";
cout<<Image<<"i\n";
}
Complex operator+(Complex&); //重载"+",实现:复数+复数
Complex operator+(float); //重载"+",实现:复数+实数
Complex& operator+=(Complex&); //重载"+=",实现:复数+=复数
Complex& operator=(Complex&); //重载"="
};
Complex Complex::operator+(Complex&c)//问1.返回值类型能否为Complex&,为什么?
{ Complex t;
t.Real =Real //当前对象之数据成员,即第一操作数之数据成员+c.Real; //第二操作数之数据成员
t.Image =Image+c.Image;
return t;
}
Complex Complex::operator+(float s)
{ Complex t;
t.Real =Real+s;
t.Image =Image;
return t;
}
Complex& Complex::operator+=(Complex&c)//问2.返回值类型为void有何不足?
{ Real+=c.Real;
Image+=c.Image;
return *this;
}
Complex& Complex::operator=(Complex&c) //问3.此函数可否省略,为什么?
{ Real=c.Real;
Image=c.Image;
return *this;
}
void main(void)
{ Complex c1(25,50),c2,c3(100,200),c4(200,400),c;
c1.Show();
c2=c1; //等价于c2.operator=(c1);
c2.Show();
c=c1+c3; c.Show();
c+=c1; c.Show(); //问4.可否实现c+=20;?若不能如何改进类Complex?
c4+=c1+c2; c4.Show();
c4=c4+200; c4.Show(); //问5.可否实现c4=200+c4;?若不能如何改进类Complex?
}
首先回答上述程序中的问题,然后为上述程序中的复数类定义比较完善的操作(至少包括:+、-、*、/、取负、+=、!=、==),并作必要的测试。
2、定义描述平面上一个点的类Point,重载++和—运算符,并区分这两个运算符的前置和后置运算。
并作必要的测试。
三、选做题
定义分数类,使其具有完善的操作。
要求:①分数的分子和分母采用int型②分数的运算结果应为最简分数。