1、运算符重载:加号运算符重载
本次主要介绍的是加号运算符的重载,当使用类创建两个对象的时候,在运算的时候直接将两个对象相加的时候,就会产生错误,编译器并不知道如何运算对象的相加函数,这时候就可以创建类函数或者全局函数,在函数中实现类中属性的加法运算。
创建这种运算的重载函数,编译器给起了一个通用的名称:“operator+”,(也就是使用这个函数名替代自己创建的普通的函数名字就可以了)然后在函数俩面实现对象属性的运算,然后返回计算结果的对象就可以了。下面代码是成员函数和全局函数的重载示例。
类内实现运算符重载的实现:
注意创建的类内类加法函数的语法,入口参数可以是“引用”,也可以使用指针的形式,使用指针的形式时,对应的对象相加的使用也要改变。
class person
{
public:
person()
{
}
person(int a, int b) :m_a(a), m_b(b)
{
}
person operator+(person& p)
{
person exam;
exam.m_a = this->m_a + p.m_a;
exam.m_b = this->m_b + p.m_b;
return exam;
}
int m_a;
int m_b;
};
void main(void)
{
person p1(1, 2);
person p2(10, 20);
//运算时,首先调用p1内的“operator+”函数,传入参数p2,返回给p3(隐式创建)
person p3 = p1 + p2;
cout << "p3Data:" << p3.m_a<<"\r\n" << p3.m_b << endl;
system("pause");
}
class person
{
public:
person()
{
}
person(int a, int b) :m_a(a), m_b(b)
{
}
person operator+(person* p)
{
person exam;
exam.m_a = this->m_a + p->m_a;
exam.m_b = this->m_b + p->m_b;
return exam;
}
int m_a;
int m_b;
};
void main(void)
{
person p1(1, 2);
person p2(10, 20);
//运算时,首先调用p1内的“operator+”函数,传入参数&p2(类函数的入口参数使用指针)
//返回给p3(隐式创建)
person p3 = p1 + &p2;
cout << "p3Data:" << p3.m_a<<"\r\n" << p3.m_b << endl;
system("pause");
}
全局函数实现运算符重载的实现:
class person
{
public:
person()
{
}
person(int a, int b) :m_a(a), m_b(b)
{
}
int m_a;
int m_b;
};
person operator+(person& P1,person& P2)
{
person exam;
exam.m_a = P1.m_a + P2.m_a;
exam.m_b = P1.m_b + P2.m_b;
return exam;
}
void main(void)
{
person p1(1, 2);
person p2(10, 20);
person p3 = p1 + p2;
cout << "p3Data:" << p3.m_a<<"\r\n" << p3.m_b << endl;
system("pause");
}
函数实现加法运算符(变量为入口参数):
class person
{
public:
person()
{
}
person(int a, int b) :m_a(a), m_b(b)
{
}
int m_a;
int m_b;
};
person operator+(person& P1,int a)
{
person exam;
exam.m_a = P1.m_a + a;
exam.m_b = P1.m_b + a;
return exam;
}
void main(void)
{
person p1(1, 2);
person p2(10, 20);
person p3 = p1 + 10;
cout << "p3Data:" << p3.m_a<<"\r\n" << p3.m_b << endl;
system("pause");
}
2、"<<"左移运算符重载
“<<”左移运算符的重载是为了实现使用“cout”输出的时候,给了对象名,直接输出对象中的所有属性,这里需要注意的是,这个算法只能通过全局函数实现,不能通过类内函数实现。下面给出示例代码:
下面的代码就是介绍了类内“<<”运算符重载不能实现的原因。
class person
{
public:
person()
{
}
person(int a, int b) :m_a(a), m_b(b)
{
}
//利用函数重载 左移运算符
//相当于p.operator<<(cout),这时候对象p在cout的左边,相当于p<<cout
//显然这样的逻辑是错误的。所以不能在类内函数实现左移运算符重载
void operator<<(ostream cout)
{
}
int m_a;
int m_b;
};
void main(void)
{
system("pause");
}
下面使用类外的全局函数实现“<<”运算符的重载:
class person
{
//全局函数的友元使用,为了访问私有属性
friend ostream& operator<<(ostream& out, person& p);
public:
person()
{
}
person(int a, int b) :m_a(a), m_b(b)
{
}
private:
int m_a;
int m_b;
};
//1、全局左移运算符重载的实现,传入参数是“cout”和“person p”
//2、函数的本质相当于:operator<<(cout,p),相当于:cout<<p,这时候的前后位置是相同的
//3、函数返回cout的引用,就可以实现套环使用。
//4、“out”是函数的形参,实参是“cout”。
ostream& operator<<(ostream &out,person &p)
{
out << "m_a;" << p.m_a << "m_b:" << p.m_b << endl;
return out;
}
void main(void)
{
person p1(1,2);
person p2(10, 11);
//下面的套环中“cout << p1”==“cout”,所以后面又可以输出p2
cout << p1<<p2;
system("pause");
}
运行结果:
3、运算符重载:递增运算符重载
使用递增运算符重载实现“对象名++”作用为对象中的属性自加,自加分为两种,一种是前置++,另一种是后置++。本章节比较难理解的是前置和后置++操作的先后代码顺序,下面代码将实现两种代码实现演示:
下面是前置++和后置++的实现代码,里面需要注意的有两点:
1、前置++和后置++使用“int”进行区分;
2、ostream& operator<<(ostream& out, person p)函数使用“person p”对象的入口参数,不能使用引用的,因为person operator++(int)函数返回值是对象。person& operator++()也可以使用对象进行接收的(person p=&(*this))。
3、因为使用的ostream& operator<<(ostream& out, person p)函数的入口参数使用的是对象,这时候就调用重新创建一个局部对象,然后调用拷贝构造函数,这时候的对象和传入函数的对象是没有关系的,当然函数返回的对象也是和函数传入的对象没有关系的,这时候就不能使用“++”符号的叠加使用了,只能使用一次。如果想实现叠加使用,那么只能修改函数为:
ostream& operator<<(ostream& out, person& p)。
class person
{
friend ostream& operator<<(ostream& out, person p);
public:
person()
{
m_a=0;
m_b=0;
}
person(int a, int b) :m_a(a), m_b(b)
{
}
//重载前置++运算符
//函数的返回采用引用,可以一直对一个数据进行递增运算
person& operator++()
{
//先自加运算
m_a++;
m_b++;
//返回本身
return *this;
}
//重载后置++运算符
//void operator++(int) int代表占位参数,可以用于区分前置和后置递增
//使用后置递增的时候需要添加int展位参数,用于区分重载函数(函数名、入口参数)
person operator++(int)
{ //先记录当时的记过
person exam = *this;
//然后递增
m_a++;
m_b++;
//最后将记录结果返回
//这里注意不能使用引用返回,因为exam为局部变量,函数结束就释放掉了。
return exam;
}
private:
int m_a;
int m_b;
};
//这里person p也不能使用引用入口参数,因为重载后置++返回的不是引用,而是对象
//使用引用会报错,返回引用的可以使用对象函数入口参数接收。
ostream& operator<<(ostream& out, person p)
{
out << p.m_a << "\r\n" << p.m_b << endl;
return out;
}
void test1(void)
{
person p1(10, 20);
person p2(1, 2);
cout << (++p1) << endl;
cout << p1 << endl;
cout << (p2++) << endl;
cout << p2 << endl;
}
void main(void)
{
test1();
system("pause");
}
4、运算符重载(赋值运算符重载)
赋值运算符重载,主要就是实现创建的对象,直接使用赋值“=”进行对象的赋值;如果类中的构造函数使用的是堆内存分配的初始化,析构函数中使用的是堆指针的堆内存清理,这时候创建多个对象的时候,对象堆内存清理的时候,就会出现都多个类清理同一个地址的堆内存,多次释放就会产生错误。这个的解决方法前面已将介过一种,就是使用深拷贝函数(拷贝函数自己手动实现,手动在堆上申请新的内存,然后进行数据的拷贝);下面通过赋值运算符的方法进行解决:
可以理解为将“operator”替换成对象本身(当operator函数在类的内部的时候),在类外部的时候不可以这样理解。
class person
{
public:
person(int age)
{
//这里构造函数数据的初始化之内类变量,需要使用堆内存的申请
//如果直接使用“ *this->age =age ”的话,就会产生报错
this->age = new int(age);
}
~person()
{
if (this->age != NULL)
{
delete this->age;
this->age = NULL;
}
}
//++运算符的重载
person& operator=(person &p)
{
//系统提供的是浅拷贝实现,在堆上使用的时候,容易产生问题
//首先判断创建的对象的堆是否为空(属于对象的堆内存)
if (this->age != NULL)
{
delete this->age;
this->age = NULL;
}
//从新在堆上申请指定数据类型的内存,并拷贝赋值
this->age = new int(*p.age);
return *this;
}
int* age;
};
void test1(void)
{
person p1(10);
person p2(20);
person p3(30);
//此处相当于调用了上面类中的“++”重载函数person& operator=(person &p)
//传入参数p2返回参数参数p2(引用的方式传给p1)
//由于上面重载函数中重新申请类内存,所示创建的对象不会都指向同一个堆内存区
p1 = p2 = p3;
cout << "p1age:" << *p1.age<<endl;
cout << "p2age:" << *p2.age << endl;
cout << "p3age:" << *p3.age << endl;
}
void main(void)
{
test1();
system("pause");
}
5、关系运算符重载(等于、不等于、大于、小于等)
本节的关系运算符的重载主要就是关系首先对象间关系运算符的直接判断,在重载函数中使用逻辑判断,根据需要判断的属性,返回bool类型的数据,实际的代码如下图所示:
class person
{
public:
person(int data)
{
age = data;
}
bool operator==(person p)
{
if (this->age == p.age)
return true;
else
return false;
}
int age;
};
void test1(void)
{
person p1(10);
person p2(10);
if (p1 == p2)
{
cout << "p1和p2一样" << endl;
}
else
{
cout << "p1和p2不一样" << endl;
}
}
void main(void)
{
test1();
system("pause");
}
下面代码是实现“>”逻辑运算的重载函数的实现:
class person
{
public:
person(int data)
{
age = data;
}
bool operator>(person p)
{
if (this->age > p.age)
return true;
else
return false;
}
int age;
};
void test1(void)
{
person p1(20);
person p2(10);
if (p1 > p2)
{
cout << "p1大于p2" << endl;
}
else
{
cout << "p1小于p2" << endl;
}
}
void main(void)
{
test1();
system("pause");
}
6、函数重载(仿函数)、匿名对象
函数的重载主要是为了是实现,直接调用一些函数是西安以下需要的功能,代码中是西安的功能和子函数实现的功能是相似的。
1、 函数调用运算符号()也可以重载;
2、由于重载后使用的方式非常像函数的调用,因此称为仿函数;
3、仿函数没有固写法,非常灵活;
class person
{
public:
//注意类内重构函数的仿函数的语法:
void operator()(string data)
{
cout << data << endl;
}
};
void test1(void)
{
//创建对象使用仿函数
person p1;
p1("dada\r\n");
//使用匿名函数对象,person()实际上也创建了一个对象,
//因为是匿名的,所以调用之后直接就是释放掉了。
person()("tete\r\n");
}
void main(void)
{
test1();
system("pause");
}