用公司网站后缀做邮箱,网站cms管理后台电话号码,企业营销网站的建设,宣传册设计与制作用什么软件文章目录12 运算符重载12.1 加法运算符重载12.2 左移运算符重载12.2.1 演示与说明12.2.2 常见的友元使用#xff1a;重载运算符12.3 递增运算符重载12.4 赋值运算符重载12.5 关系运算符重载12.6 函数调用运算符重载12 运算符重载
在本讲中#xff0c;我们会设计到一…
文章目录12 运算符重载12.1 加法运算符重载12.2 左移运算符重载12.2.1 演示与说明12.2.2 常见的友元使用重载运算符12.3 递增运算符重载12.4 赋值运算符重载12.5 关系运算符重载12.6 函数调用运算符重载12 运算符重载
在本讲中我们会设计到一些使得对象操作更美观的技术——运算符重载。运算符重载是一种C多态的形式。
运算符通过重载可以实现其原本没有的含义。C允许运算符重载扩展到用户定义的类型如将两个对象相加。
我们前面实际上学过数组如果要将两个数组的对应元素相加我们需要写一个for循环来遍历数组中的元素并且分别进行相加。实际上这就是一种简单的重载我们口头上所说的arr1arr2实际上赋予了——加是对应元素相加的这层含义。
所以为了简化它的意思我们可以将对应元素相加后的新数组写为以下的形式 arr3 arr1arr2 总结上述所讲运算符重载的含义是对已有的运算符重新进行定义赋予其另一种功能以适应不同的数据类型。
重载的通用格式如下所示 operator op(argument - list) op指的是C现有的运算符例如加法运算符重载为operator ()。当然C以外的、虚构的运算符不可重载这是需要注意的。
12.1 加法运算符重载
对于内置数据类型编译器知道如何进行运算
int a 10;int b 10;int c ab
但是我们假如是下面这种情况呢
class Person
{
public:int m_A;int m_B;}Person p1;
p1 m_A 10;
p1 m_B 10;Person p2;
Person p1;
p2 m_A 10;
p2 m_B 10;Person p3 p1p2;在这种情况下C编译器就会蒙了Person是啥类型怎么还能相加
我们实际上可以编写一个成员函数来实现此功能实现两个对象相加属性后返回新的对象。而对于C来说为了指明是加法运算符的作用发生了变化故该函数统一命名为operatao 。
如果你按照它的命名规则来了那么在调用函数时你就可以使用p3 p1p2的格式去调用这个函数。
以上的方式我们叫做通过成员函数来重载号运算符除此之外我们还可以通过全局函数来重载号运算符。
让我们看看下面的例子来理解我上述的话。
#include iostream
using namespace std;//加号运算符重载
class Person
{
public://成员函数重载号/*Person operator(Person p) {Person temp;temp.m_A this-m_A p.m_A;temp.m_B this-m_B p.m_B;return temp;}*/int m_A;int m_B;private:};//全局函数重载号
Person operator(Person p1,Person p2)
{Person temp;temp.m_A p1.m_A p2.m_A;temp.m_B p1.m_B p2.m_B;return temp;
}void test01()
{Person p1;p1.m_A 10;p1.m_B 10;Person p2;p2.m_A 10;p2.m_B 10;Person p3 p1 p2;cout p3.m_A: p3.m_A endl;cout p3.m_B: p3.m_B endl;
}int main()
{test01();
}out 运算符重载也可以发生函数重载。这样的原因是可以应对多种情况。如p3 p210对于10我们并没有写出对应解决的方案函数所以如果运算符重载不能发送函数重载那么就对运算符不太友好了。
总的来说加法运算符就是使得自定义的数据类型能够按照自己想要的方式相加。需要注意的是对于内置的数据类型的操作运算符是不可改变的并且对于运算符的重载不要滥用。
12.2 左移运算符重载
12.2.1 演示与说明
左移运算符指的是我们在输出的时候使用的那个运算符。
coutaendl;如果是对于内置的基本数据类型那肯定是可以利用左移运算符来进行输出的。但是如果是对象呢
Person p;
coutpendl;这样的对象输出的结果肯定是不被允许的如下所示。 对此我们可以通过重载左移运算符来获得我们想要的效果。
我们前面说过可以通过成员函数和全局函数来重载但是对于左移运算符其并不能在成员函数中被重载因为逻辑不对。所以对于通常的左移运算符重载我们都是在全局函数中去实现它。
试着敲一下下面的代码你就能理会其中的思想了。
#include iostream
using namespace std;class Person
{
public:int m_A;int m_B;
};//只能利用全局函数重载左移运算符
void operator(ostream cout, Person p)
{cout m_A p.m_A m_B p.m_B ;
}void test01()
{Person p1;p1.m_A 10;p1.m_B 20;cout p1 ;
}int main()
{test01();system(pause);
}out 我们实际上可以尝试在重载过后的写上这样的代码:
coutp1endl;很快地你会发现报错了。报错的原因是因为你的重载函数并没有返回值而对于cout之所以可以使用两个左移运算符是因为其内含有链式编程的思想。故如果想要使得可以连续使用我们必须将函数的返回值改为cout即可。
顺便提一句cout是ostream实例化的结果即输出对象。 ostream对象 ostream对象是指输出流对象通常来说cout输出的对象是指显示器当然还有输入流对象ofstream这些我们到后面再去提及。 我们将以上的代码改写为如下即可实现多次使用
#include iostream
using namespace std;class Person
{
public:int m_A;int m_B;
};//只能利用全局函数重载左移运算符
ostream operator(ostream cout, Person p)
{cout m_A p.m_A m_B p.m_B ;return cout;
}void test01()
{Person p1;p1.m_A 10;p1.m_B 20;cout p1 endl;
}int main()
{test01();system(pause);
}out 为什么使用引用 在上述的代码中实际上两个位置使用到了引用。返回值和参数是引用的原因是我们自始至终都想这对cout这个对象做功能上的修改而不是从ostream再创建一个cout对象然后赋予它新功能。故我们要加上引用。 12.2.2 常见的友元使用重载运算符
在实际开发中我们实际上会把成员属性写入私有这样的话对于重载函数无法访问我们只需要利用友元即可解决这个问题。
#include iostream
using namespace std;class Person
{friend ostream operator(ostream cout, Person p);
private:int m_A 10;int m_B 20;
};//重载左移运算符
ostream operator(ostream cout, Person p)
{cout m_A p.m_A m_B p.m_B;return cout;
}void test01()
{Person p1;cout p1 endl;
}int main()
{test01();
}out 12.3 递增运算符重载
我们来看看递增运算符的原理。
int a 10;cout a endl;//11
cout a endl; //结果为11cout bendl;//10
cout b endl;//11对于a其原理为先做操作再输出而对于b其原理为先输出再。
同样地我们对对象做自增操作其原理如下
class MyInteger
{
public:MyInteger(){m_Num 0;}private:int m_Num;
}MyInteger myint;
cout myintendl; //0
cout myint endl; //1
cout myint endl; //1
cout myint endl; //2我们来试着实现上述的原理
#include iostream
using namespace std;class MyInteger
{friend ostream operator(ostream cout, MyInteger myint);
public:MyInteger() {m_Num 0;}//局部函数重载运算符(前置)MyInteger operator() //返回一个引用是为了一直对一个数据进行操作{m_Num;return *this;}//局部函数重载运算符(后置)MyInteger operator(int) //不能返回引用因为此时返回值是局部变量{//1 记录当前结果MyInteger temp *this;//2 递增m_Num;//3 将记录结果返回return temp;}private:int m_Num;
};ostream operator(ostream cout, MyInteger myint)
{cout myint.m_Num;return cout;
}void test01()
{MyInteger myint;cout myint endl;
}void test02()
{MyInteger mying;cout mying endl;cout mying endl;
}int main()
{test01();test02();system(pause);
}12.4 赋值运算符重载
赋值运算符的重载原理涉及到深浅拷贝我们从代码中理解比较好。
#include iostream
using namespace std;//赋值运算符重载
class Person
{
public:Person(int age) {m_Age new int(age);}~Person() {if (m_Age ! NULL) {delete(m_Age);m_Age NULL;}}int* m_Age;
};void test01()
{Person p1(18);Person p2(20);p2 p1;//赋值操作cout p1的年龄为 *p1.m_Age endl;cout p2的年龄为 *p2.m_Age endl;}int main()
{test01();system(pause);return 0;
}从以上的代码中我们会发现无法运行根本原因是因为 也就是说根本原因是因为原来的赋值运算符提供的是一个浅拷贝的过程但是我们想要的是一个深拷贝的效果故我们需要重载赋值运算符。如下所示
#include iostream
using namespace std;//赋值运算符重载
class Person
{
public:Person(int age) {m_Age new int(age);}~Person() {if (m_Age ! NULL) {delete(m_Age);m_Age NULL;}}//重载赋值运算符Person operator(Person p) {//对于编译器来说其提供的是浅拷贝//我们应该需要用深拷贝//应该先判断是否有属性在堆区如果有先释放干净然后再深拷贝if (m_Age ! NULL) {delete m_Age;m_Age NULL;}//深拷贝m_Age new int(*p.m_Age);//记住要返回指针才能实现链式编程return *this;}int* m_Age;
};void test01()
{Person p1(18);Person p2(20);Person p3(30);p3 p2 p1;//赋值操作cout p1的年龄为 *p1.m_Age endl;cout p2的年龄为 *p2.m_Age endl;cout p3的年龄为 *p3.m_Age endl;
}int main()
{test01();system(pause);return 0;
}out 12.5 关系运算符重载
对于自定义的数据类型C是无法提供对比方式的如、、等。为此我们需要重载关系运算符。
让我们用以下的代码来解决这个问题
#include iostream
using namespace std;//重载关系运算符
class Person
{
public:Person(string name, int age) {m_Name name;m_Age age;};//重载 号bool operator(Person p) {if (this-m_Name p.m_Name this-m_Age p.m_Age) {return true;}return false;}string m_Name;int m_Age;private:};void test01()
{Person p1(Tom, 18);Person p2(jarry, 19);//Person p2(Tom, 18);if (p1 p2) {cout 相同 endl;}else{cout 不相同 endl;}
}int main()
{test01();
}12.6 函数调用运算符重载
函数调用运算符()也可以重载需要注意的是由于重载后使用的方式非常像函数的调用因此称为仿函数。仿函数没有固定的写法其风格多变。
让我们试着敲一下下面的代码
#include iostream
using namespace std;
#include string//函数调用运算符重载
//打印输出类
class MyPrint
{
public://重载函数调用运算符void operator()(string test) {cout test endl;}
};class MyAdd
{
public://重载例子2int operator()(int num1, int num2){return num1 num2;}
};void test01()
{MyPrint myPrint;myPrint(hello world);
}void test02()
{MyAdd myadd;cout ret myadd(100, 200) endl;
}int main()
{test01();test02();
}C和Java一样也是创建一个匿名对象匿名对象使用后当场销毁。如在上例中我想创建一个匿名对象只需
MyAdd()(100,100)