运算符重载
- 实现自定义类型的运算
- 对于内置数据类型的表达式的运算是不可以改变的 (1+1不能改成3)
- 四个运算符不能重载, 八个点
::
, .
, .*
, :?
加号运算符重载
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;
}
void test01()
{
Person p1;
p1.m_A = 10;
p2.m_B = 10;
Person p2;
p2.m_A = 20;
p2.m_B = 20;
Person p3 = p1 + p2;
}
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;
}
Person operator+(Person& p, int a)
{
Person temp;
temp.m_A = p.m_A + a;
temp.m_B = p.m_B + a;
return temp;
}
void test01()
{
Person p1;
p1.m_A = 10;
p2.m_B = 10;
Person p2;
p2.m_A = 20;
p2.m_B = 20;
Person p3 = p1 + p2;
Person p4 = p1 + 4;
}
左移运算符
- 输出自定义数据类型
成员运算符重载左移运算符
- 一般不使用成员函数重载<<运算符, 因为无法实现cout在左侧
class Person
{
public:
Person(int a, int b): a(a), b(b) {}
void operator<<(ostream& cout)
{
cout<<a<<" "<<b<<endl;
}
int a;
int b;
};
int main(){
Person p(1,2);
p<<cout;
return 0;
}
1 2
Program ended with exit code: 0
全局函数重载左移运算符
- 不能通过更改形参的顺序, 来实现p<<cout, 会报错.
- 必须第一个行参是ostream对象引用, 第二个是自定义数据类型
void operator<<(ostream& cout, Person& p)
{
cout<<p.a<<" "<<p.b<<endl;
}
int main()
{
operator<<(cout, p);
cout<<p;
}
- 上述这种情况, 不能进行链式输出 (cout<<p<<endl;) , 因为返回值是void, 想要实现链式输出, 只需要把返回对象改为ostream& (返回引用作为左值)
- cout是一个内置的已经存在的ostream对象, 形参中可以用其自定义改名, 但是传递的实参必须是cout
ostream& operator<<(ostream& cout, Person& p)
{
cout<<p.a<<" "<<p.b;
return cout;
}
int main(){
Person p(1,2);
operator<<(cout, p)<<endl;
cout<<p<<endl;
return 0;
}
- 一般成员设为私有属性, 重载左移运算符的全局函数作为友元函数
class Person
{
friend ostream& operator<<(ostream& cout, Person& p);
public:
Person(int a, int b): a(a), b(b) {}
void operator<<(ostream& cout)
{
cout<<a<<" "<<b<<endl;
}
private:
int a;
int b;
};
ostream& operator<<(ostream& cout, Person& p)
{
cout<<p.a<<" "<<p.b;
return cout;
}
int main(){
Person p(1,2);
operator<<(cout, p)<<endl;
cout<<p<<endl;
return 0;
}
递增运算符重载
重载的条件是 作用域, 函数名, 参数列表, 和返回值无关.
- 后置自增运算符 (可以连续前置递增, ++(++m)可以)
- 取值, 复制, 原值++, 返回复制值
本质调用 : int a; obj.operator++(a);
- 前置自增运算符 (不可以连续后置递增, (m++)++ 报错)
- 取值, 原值++, 返回原值
本质调用 : obj.operator++();
class MyInt
{
friend ostream& operator<<(ostream& cout, MyInt m);
public:
MyInt(int a) : a(a) {}
MyInt(){}
MyInt& operator++()
{
a++;
return *this;
}
MyInt operator++(int)
{
MyInt temp = *this;
a++;
return temp;
}
private:
int a;
};
ostream& operator<<(ostream& cout, MyInt m)
{
cout<<m.a;
return cout;
}
int main(){
MyInt m(1);
cout<<"m : "<<m<<endl;
cout<<"++(++m) : "<<++(++m)<<endl;
cout<<"m : "<<m<<endl;
cout<<"m++ : "<<m++<<endl;
cout<<"m : "<<m<<endl;
return 0;
}
赋值运算符重载
- C++编译器至少给一个类添加4个函数
- 默认构造函数(无参, 函数体为空)
- 默认析构函数(无参, 函数体为空)
- 默认拷贝构造函数, 对属性进行值拷贝
- 赋值运算符operator=, 对属性进行值拷贝
- 如果类中有属性指向堆区, 赋值操作时会造成
深浅拷贝
问题 (堆区重复释放)
赋值运算符是会返回一个值的, 因此有连续赋值操作a=b=c
- 初始化的时候用赋值符号. Student s2 = s1, 只是在栈上创建了一个Student变量, 指向了s1对象, 并没有创建新的对象. 因此如果也会发生重复释放的问题, s2在函数执行完后自动调用s1的析构函数, s1对象自己又回调用一次.
- 常规的赋值操作, 是把对象的数据全部拷贝一份到新的对象
class Student
{
public:
Student(int age)
{
this->age = new int(age);
}
Student(){}
~Student()
{
cout<<"~Student"<<endl;
if(age != NULL)
{
delete age;
age = NULL;
}
}
Student& operator=(Student& s)
{
if(age != NULL)
{
delete age;
age = NULL;
}
age = new int(*s.age);
return *this;
}
int *age;
};
int main(){
Student s1(10);
Student s2(20);
Student s3;
s3 = s2 = s1;
cout<<s1.age<<endl;
cout<<s2.age<<endl;
cout<<s3.age<<endl;
return 0;
}
关系运算符重载
class Car
{
public:
Car(int n, string s) : num(n), color(s){}
bool operator==(Car& c)
{
if(this->num == c.num && this->color == c.color)
return true;
else
return false;
}
bool operator!=(Car& c)
{
if(this->num == c.num && this->color == c.color)
return false;
else
return true;
}
int num;
string color;
};
int main(){
Car c1(5, "white");
Car c2(5, "white");
Car c3(6, "white");
cout<<(c1==c2)<<endl;
cout<<(c1!=c3)<<endl;
cout<<(c2==c3)<<endl;
return 0;
}
函数调用运算符重载
函数调用运算符()
也可以重载- 由于重载后使用的方式非常像函数的调用, 因此称为
仿函数
- 仿函数没有固定写法, 非常灵活
数字常量不能当作实参传入引用的形参
class MyPrint
{
public:
void operator()(string s)
{
cout<<s<<endl;
}
};
void MyPrint2(string s)
{
cout<<s<<endl;
}
void test01()
{
MyPrint myprint;
myprint("hello");
MyPrint2("hello2");
}
class MyAdd
{
public:
int operator()(int a, int b)
{
return a+b;
}
};
void test02()
{
MyAdd myadd;
int c = myadd(1,2);
cout<<c<<endl;
cout<<MyAdd()(100, 100)<<endl;
}