专门做设计的网站,客户资料管理系统,海淀区网站制作公司,张家界建设局网站电话号码运算符重载#xff1a; 运算符重载概念#xff1a;对已有的运算符重新进行定义#xff0c;赋予其另一种功能#xff0c;以适应不同的数据类型 运算符的重载实际是一种特殊的函数重载#xff0c;必须定义一个函数#xff0c;并告诉C编译器#xff0c;当遇到该重载的运算符…运算符重载 运算符重载概念对已有的运算符重新进行定义赋予其另一种功能以适应不同的数据类型 运算符的重载实际是一种特殊的函数重载必须定义一个函数并告诉C编译器当遇到该重载的运算符时调用此函数。这个函数叫做运算符重载函数通常为类的成员函数
定义运算符重载函数的一般格式返回值类型 类名::operator重载的运算符(参数表) {.......}
operator是关键字它与重载的运算符一起构成函数名。因函数名的特殊性C编译器可以将这类函数识别出来。
加号运算符重载
作用实现两个自定义数据类型相加的运算 1.成员函数实现 号运算符重载 #include iostream
using namespace std;//加号运算符重载class Person
{
public://1 成员函数实现 号运算符重载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;
};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();system(pause);return 0;
}2.全局函数重载
class Person
{
public://1 成员函数实现 号运算符重载/*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;
};//2.全局函数重载号
Person operator(Person p1, const Person p2)
{Person temp;temp.m_A p1.m_A p2.m_A;temp.m_B p1.m_B p2.m_B;return temp;
}//3 运算符重载 可以发生函数重载
Person operator(Person p1, int num)
{Person temp;temp.m_A p1.m_A num;temp.m_B p1.m_B num;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 p2 p1; //相当于 p2.operaor(p1)Person p3 p1 p2;//全局函数重载本质调用Person p3 operator(p1, p2);Person p3 p1 p2;//cout p3.m_A p3.m_A endl;cout p3.m_B p3.m_B endl;
}int main()
{test01();system(pause);return 0;
}
2.左移运算符重载 作用可以输出自定义数据类型 #include iostream
using namespace std;//左移运算符重载class Person
{friend ostream operator(ostream cout, Person p);public:Person(int a, int b){this-m_A a;this-m_B b;}
private:
//成员函数 实现不了 p cout 不是我们想要的效果//void operator(Person p){//}int m_A;int m_B;
};//全局函数实现左移重载
ostream operator(ostream cout, Person p) //本质 operator(cout,p) 简化coutp
{cout m_A p.m_A m_B p.m_B;return cout;
}void test01()
{Person p(10,10);//p.m_A 10;//p.m_B 10;cout phello worldendl; //链式编程 输出一个对象就能打印他的属性
} int main()
{test01();system(pause);return 0;
} 总结重载左移运算符配合友元可以实现输出自定义数据类型 3.递增运算符重载 作用 通过重载递增运算符实现自己的整型数据 总结前置递增返回引用后置递增返回值 先写一个输出整形数据的
class MyInteger
{friend ostream operator(ostream cout, MyInteger myint);
public:MyInteger() {m_Num 0;}private:int m_Num;
};//重载左移运算符
ostream operator(ostream cout, MyInteger myint)
{cout myint.m_Num endl; //全局函数想要访问私有属性return cout;
}
void test01()
{MyInteger myint;cout myint endl;}int main()
{test01();system(pause);return 0;
}输出结果 0 class MyInteger
{friend ostream operator(ostream cout, MyInteger myint);
public:MyInteger() {m_Num 0;}//重载前置运算符 返回引用为了一直对一个数据进行递增操作MyInteger operator(){//先m_Num;//再返回return *this;}//重载后置运算符 //int代表占位参数可以用于区分前置和后置递增MyInteger operator(int){//先记录当时结果MyInteger temp *this;//后递增m_Num;//最后将记录结果做返回return temp;}private:int m_Num;
};//重载左移运算符
ostream operator(ostream cout, MyInteger myint)
{cout myint.m_Num endl; //全局函数想要访问私有属性return cout;
}
void test01()
{MyInteger myint;cout myint endl;}void test02()
{MyInteger myint;cout myint endl;cout myint endl;
}int main()
{// test01();test02();system(pause);return 0;
}4.赋值运算符重载 c 编译器至少给一个类添加 4 个函数 1. 默认构造函数 ( 无参函数体为空 ) 2. 默认析构函数 ( 无参函数体为空 ) 3. 默认拷贝构造函数对属性进行值拷贝 4. 赋值运算符 operator, 对属性进行值拷贝 如果类中有属性指向堆区做赋值操作时也会出现深浅拷贝问题 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;
}
上示代码会崩; 崩溃原因堆区内存重复释放 解决方法 示例如下
class Person
{
public:Person(int age){m_Age new int(age); //把数据创建在堆区 }~Person(){if (m_Age ! NULL){delete m_Age;m_Age NULL;}} //释放堆区内存 //重载 赋值运算符 编译器默认提供 是一个浅拷贝的操作创建在堆区d的属性就会出现堆区内存重复释放Person operator(Person p) //返回引用{//编译器提供的代码是浅拷贝//m_Age p.m_Age;//应该先判断是否有属性在堆区如果有先释放干净然后再深拷贝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;
} 拷贝构造函数 与赋值重载函数的区别。 总结: 浅赋值与深复制。 什么时候使用深拷贝和深赋值。 在类型设计中使用动态内存或使用内核对象时必须重新实现拷贝构造函数和赋值重载 5.关系运算符重载 作用 重载关系运算符可以让两个自定义类型对象进行对比操作 如下图对于内置类型来说编译器可以正常运行但是对于自定义类型来说程序会出现崩溃现象。 class Person
{
public:Person(string name, int age) //用构造函数进行赋初值{m_Name name;m_Age age;}string m_Name;int m_Age;};void test01()
{Person p1(Tom, 18);Person p2(Tom, 18);if (p1 p2) 、//err{cout a和b相等 endl;}else{cout a和b不相等 endl;}
}int main()
{test01();system(pause);return 0;
} 对于
重载关系运算符可以让两个自定义类型对象进行对比操作
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;}else{return false;}}string m_Name;int m_Age;};void test01()
{Person p1(Tom, 18);Person p2(Tom, 18);if (p1 p2) //err 需要重载{cout p1和p2相等 endl;}else{cout p1和p2不相等 endl;}
}int main()
{test01();system(pause);return 0;
} 对于 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;}else{return false;}}bool operator!(Person p){if (this-m_Name p.m_Name this-m_Age p.m_Age){return false;}else{return true;}}string m_Name;int m_Age;};void test01()
{Person p1(Tom, 18);Person p2(Jerry, 18);if (p1 p2) //err 需要重载{cout p1和p2相等 endl;}else{cout p1和p2不相等 endl;}if (p1 ! p2) //err 需要重载{cout p1和p2是不相等 endl;}else{cout p1和p2相等 endl;}
}int main()
{test01();system(pause);return 0;
}
运行结果 6.函数调用运算符重载 函数调用运算符 () 也可以重载 由于重载后使用的方式非常像函数的调用因此称为仿函数 仿函数没有固定写法非常灵活 //打印输出类
class MyPrint
{
public://重载函数调用运算符 也称为仿函数void operator()(string test) //()代表了函数名 (string test) 形参列表{cout test endl;}
};void MyPrint02(string test)
{cout test endl;
}void test01()
{MyPrint myPrint;myPrint(hello world);//由于使用起来非常类似于函数调用因此称为仿函数MyPrint02(hello world); //函数调用
}//仿函数非常灵活 没有固定的写法 依照需求 写对应的仿函数
//加法类class MyAdd //实现两数相加
{
public:int operator()(int num1,int num2){return num1 num2;}
};void test02()
{MyAdd myadd; //先创建对象int ret myadd(100, 100);cout ret ret endl;//匿名对象调用 类型加小括号cout MyAdd()(100,100) MyAdd()(100, 100) endl;
}int main()
{test01();//test02();system(pause);return 0;
}
运算符重载函数的总结: 1、运算符重载函数的函数名必须为关键字operator加一个合法的运算符。在调用该函数时将右操作数作为函数的实参。 2、当用类的成员函数实现运算符的重载时运算符重载函数的参数(当为双目运算符时)为一个或(当为单目运算符时)没有。运算符的左操作数一定是对象因为重载的运算符是该对象的成员函数而右操作数是该函数的参数。 3、单目运算符“”和“存在前置与后置问题.
前置“格式为: 返回类型 类名::operator(){......} 而后置“格式为: 返回类型 类名::operator(int){......} 后置“”中的参数int仅用作区分并无实际意义可以给一个变量名也可以不给变量名。
4、C中只有极少数的运算符不允许重载
重载运算符有以下几种限制 不可臆造新的运算符. 不能改变运算符原有的优先级、结合性和语法结构,不能改变运算符操作数的个数. 运算符重载不宜使用过多 重载运算符含义必须清楚不能有二义性