运算符重载参数个数(运算符重载你一看就懂)
运算符重载参数个数(运算符重载你一看就懂)在讨论运算符重载之前我们先来介绍下函数重载,函数重载就是对一个已有的函数运算符重载的使用规则C 强大的原因之一是支持泛型编程。泛型编程使得算法可以独立于数据类型存在。自定义的数据类型通过操作符重载具有了和内建类型同样的使用接口,然后C 的模板加持下,你的算法可以利用这种接口一致性,实现泛化。下面介绍下运算符重载一、运算符重载
经验分享:
运算符重载一般会在类的自定义数据结构中使用,常用的有赋值运算符(主要进行类与类的赋值,是浅拷贝,对于指针之类的要进行深拷贝)。==运算符,判断类之间是否相等。在STL模板库类的内部也使用了大量的运算符重载。另外在一些关于计算的数学的类中,也会重写 =、*=、-=、/= 等等运算符。
运算符重载的意义:
运算符重载提高了开发效率,增加代码的可复用性,很多时候简化了问题。
C 强大的原因之一是支持泛型编程。泛型编程使得算法可以独立于数据类型存在。自定义的数据类型通过操作符重载具有了和内建类型同样的使用接口,然后C 的模板加持下,你的算法可以利用这种接口一致性,实现泛化。
下面介绍下运算符重载
一、运算符重载
运算符重载的使用规则
在讨论运算符重载之前我们先来介绍下函数重载,函数重载就是对一个已有的函数
赋予新的含义,使之实现新功能,因此一个函数名就可以代表不同功能的函数
运算符重载:简单点来说就是赋予 运算符 一个新的功能,新的运算规则
当然了基础数据类型编译器知道运算规则,所以可以直接运算
下面来介绍下运算符重载的步骤:
1、写出函数名 operator 重要的运算符 (比如 :operator *: operator* []: operator[])
2、根据运算需要的操作数写出 参数列表,加法需要两个操作数,分别写出左和右操作数:operator (c1 c2);
3、根据需要写出函数返回值:Complex operator (const Complex &c1 const Complex &c
class Complex
{
friend Complex add (const Complex &c1 const Complex &c2);
friend Complex operator (const Complex &c1 const Complex &c2);
friend Complex operator (const Complex &c1 int num);
public:
Complex()
{
a = 0;
b = 0;
}
Complex(int a int b)
{
this->a = a;
this->b = b;
}
void print()
{
printf ("%d %di\n" a b);
}
Complex add(const Complex &c2)
{
Complex tmp(a c2.a b c2.b);
return tmp;
}
Complex operator-(const Complex &c2) const
{
Complex tmp(a-c2.a b-c2.b);
return tmp;
}
private:
int a; // 实部
int b; // 虚部
};
Complex add(const Complex &c1 const Complex &c2)
{
Complex tmp(c1.a c2.a c1.b c2.b);
return tmp;
}
// 全局函数
// operator 可以理解成一个函数名
Complex operator (const Complex &c1 const Complex &c2)
{
Complex tmp(c1.a c2.a c1.b c2.b);
return tmp;
}
Complex operator (const Complex &c1 int num)
{
Complex tmp(c1.a num c1.b);
return tmp;
}
int main3_2()
{
Complex c1(1 2) c2(3 4) c;
// c = c1 c2;
// 全局使用
c = operator (c1 c2);
// 内部使用
c = c1.add(c2);
// 运算符重载 内部 和 全局函数 同时只能存在一个
// 全局到内部的转换:隐藏左操作数
c = c1.operator-(c2);
c = c1 - c2;
c.print();
return 0;
}
二、单目运算符
前置自增运算符
int main4_1()
{
Complex c(1 2) c2(3 4);
// 复数自增 实部虚部同时自增
// operator
// operator (c) ====> operator (Complex &c)
// void operator (Complex &c)
// c;
// c.print();
Complex c1 = c; // Complex c1 = operator (c)
c1 = c c2; // c1 = c c2; (operator (c)).operator (c2)
c1.print();
// 内部 Complex& operator --(Complex &c) ===> Complex& operator --()
--c1;
c1.print();
return 0;
}
后置自增运算符
// 后置 有一个占位参数来与 前置 进行区分
// 先使用,再自增
Complex operator (Complex &c int)
{
// 定义一个临时对象来保存 c 的值
Complex tmp(c.a c.b);
c.a ;
c.b ;
return tmp;
}
// 后置自增运算符:c
int main()
{
Complex c c1(1 2) c2(3 4);
// Complex operator (Complex &c int)
c = c1 c2;
c.print();
c1.print();
// 内部 :Complex operator--(Complex &c int) ====> Complex operator--(int)
c1--;
c1.print();
return 0;
}
三、左移与右移操作符
<< 是一个操作符 我们可以重载它的功能
cout 是一个对象 cout 是 ostream 的一个对象
operator<< (cout c1)
operator<< (ostream &out const Complex &c);
左移和右移操作只能用友元函数进行重载,写成全局函数,无法写成内部函数,因为无法修改 ostream 类
四、赋值运算符
Teacher &operator=(const Teacher &obj)
{
// 函数入口参数检查 如果是自己直接返回
if (&obj == this)
return *this;
// 1、释放原有的空间
if (name != NULL)
delete [] name;
// 2、开辟新空间
this->name = new char[20];
// 复制
this->age = obj.age;
strcpy (this->name obj.name);
return *this;
}
默认的赋值运算是一个 浅拷贝 的过程
五、函数调用运算符
class Test
{
public:
Test(int a)
{
this->a = a;
}
void operator()(int b1 int b2)
{
printf ("a = %d\n" a);
}
private:
int a;
};
int main7_1()
{
// 定义对象
Test a(10);
// ()是函数调用运算符
// operator()(Test &a) ===> operator()()
a(1 2); // a 是一个对象, 不是一个函数, 但是它的行为和函数很像 这样的使用 叫仿函数
return 0;
}
六、逻辑运算符
逻辑运算符的短路规则:
|| 有一个表达式为真,后面的表达式将不再执行
&& 有一个表达式为假,后面的表达式将不再执行
Test8_1 t1(0) t2(1) t3(2);
bool operator &&(Test8_1 &t1 Test8_1 &t2); ===> bool operator &&(Test8_1 &t2);
t1.operator&& (t2 = t3)
逻辑运算符重载无法实现短路运算规则
t1 && (t2 = t3);
七、数组下标运算符的重载
[]运算符是用于访问数据对象的元素
重载格式类型 类::operator[](类型);
class Array
{
public:
Array (int len = 0)
{
this->len = len;
p = new int[len];
}
int &operator[](int index)
{
return p[index];
}
private:
int len;
int *p
int main()
{
Array a(10);
for (int i = 0; i < 10; i )
{
// operator[] (Array &a int i) ==> operator[] ( int i)
// a.operator[](i) = i;
a[i] = i;
}
return 0;
}