4.提高
1.运算符重载机制
编译器实现运算符重载实际上就是通过函数重载实现的,可分为全局函数方式,也可分为成员函数方式进行重载,并没有改变原操作符的属性和语义。只是针对某个特定类定义一种新的数据类型操作。
2.重载赋值运算符
- 赋值运算符重载用于对象数据的复制
- operator= 必须重载为成员函数
- 重载函数原型为:
类型 & 类名 :: operator= ( const 类名 & ) ;
结论:
1 先释放旧的内存
2 返回一个引用
3 =操作符 从右向左
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//
class Name
{
public:
Name(const char *myp)
{
m_len = strlen(myp);
m_p =(char *) malloc(m_len + 1); //
strcpy(m_p, myp);
}
//Name obj2 = obj1;
//解决方案: 手工的编写拷贝构造函数 使用深copy
Name(const Name& obj1)
{
m_len = obj1.m_len;
m_p = (char *)malloc(m_len + 1);
strcpy(m_p, obj1.m_p);
}
//obj3 = obj1; // C++编译器提供的 等号操作 也属 浅拷贝
//obj3.operator=(obj1)
Name& operator=(Name &obj1)
{
//先释放旧的内存
if (this->m_p != NULL)
{
delete[] m_p;
m_len = 0;
}
//2 根据obj1分配内存大小
this->m_len = obj1.m_len;
this->m_p = new char [m_len+1];
//把obj1赋值
strcpy(m_p, obj1.m_p);
return *this;
}
~Name()
{
if (m_p != NULL)
{
free(m_p);
m_p = NULL;
m_len = 0;
}
}
protected:
private:
char *m_p ;
int m_len;
};
//对象析构的时候 出现coredump
void objplaymain()
{
Name obj1("abcdefg");
Name obj2 = obj1; //C++编译器提供的 默认的copy构造函数 浅拷贝
Name obj3("obj3");
obj3 = obj1; // C++编译器提供的 等号操作 也属 浅拷贝
//obj3.operator=(obj1)
//operato=(Name &obj1)
obj1 = obj2 = obj3;
//obj2.operator=(obj3);
//obj1 = void;
}
void main()
{
objplaymain();
cout<<"hello..."<<endl;
system("pause");
return ;
}
3.重载下标运算符
- [ ]运算符用于访问数据对象的元素
- 重载格式 类型 类 :: operator[] ( 类型 ) ;
- 只能用成员函数重载,不能用友元函数重载
示例:
设 x 是类 X 的一个对象,则表达式
x [ y ]
可被解释为
x . operator [ ] ( y )
函数返回值当左值需要返回一个引用!
4.带下标和相等操作符的数组类
- 类的头文件
#ifndef NEWARRAY_H
#define NEWARRAY_H
#include <iostream>
#include <stdlib.h>
class NewArray
{
public:
NewArray();
NewArray(int _len);
NewArray(const NewArray & obj);
~NewArray();
void setData(int index,int var);
int getData(int index);
int length();
int& operator[](int i);
NewArray& operator=(NewArray& obj);
bool operator==(NewArray& obj);
bool operator!=(NewArray& obj);
private:
int m_len;
int *m_buf;
};
#endif // NEWARRAY_H
- 类的实现文件
#include "newarray.h"
NewArray::NewArray()
{
m_buf = NULL;
m_len = -1;
}
NewArray::NewArray(int _len)
{
if(_len < 0)
_len = 0;
m_len = _len;
m_buf = new int[m_len];
}
NewArray::NewArray(const NewArray & obj)
{
m_len = obj.m_len;
m_buf = new int[m_len];
for(int i = 0;i < m_len;i++)
{
m_buf[i] = obj.m_buf[i];
}
}
NewArray::~NewArray()
{
if(m_buf != NULL)
{
delete []m_buf;
m_buf = NULL;
m_len = -1;
}
}
void NewArray::setData(int index,int var)
{
m_buf[index] = var;
}
int NewArray::getData(int index)
{
return m_buf[index];
}
int NewArray::length()
{
return m_len;
}
int& NewArray::operator[](int i)
{
return m_buf[i];
}
NewArray& NewArray::operator=(NewArray& obj)
{
if(m_buf != NULL)
{
delete []m_buf;
m_len = -1;
m_buf = NULL;
}
m_len = obj.m_len;
m_buf = new int[m_len];
for(int i = 0;i < m_len;i++)
{
m_buf[i] = obj.m_buf[i];
}
return *this;
}
bool NewArray::operator==(NewArray& obj)
{
if(m_len != obj.m_len)
{
return false;
}
for(int i = 0;i < m_len;i++)
{
if(m_buf[i] != obj.m_buf[i])
{
return false;
}
}
return true;
}
bool NewArray::operator!=(NewArray& obj)
{
return !((*this) == obj);
}
- 测试文件
#include "newarray.h"
using namespace std;
int main()
{
NewArray a1(10);
for (int i=0; i<a1.length(); i++)
{
//成员函数方式赋值
a1.setData(i, i);
//下标运算符重载赋值
a1[i] = i;
//函数返回值当左值,需要返回一个引用
//a1.operator [i]
}
cout<<"\na1: ";
for (int i=0; i<a1.length(); i++)
{
//cout<<a1.getData(i)<<" ";//成员函数方式获取元素
//下标运算符方式获取数组元素
cout<<a1[i]<<"\t";
}
cout<<endl;
//赋值运算符重载
NewArray a2 = a1;
cout<<"\na2: ";
for (int i=0; i<a2.length(); i++)
{
cout<<a2.getData(i)<<" ";
}
cout<<endl;
//3
NewArray a3(5);
{
a3 = a1;
a3 = a2 = a1;
cout<<"\na3: ";
for (int i=0; i<a3.length(); i++)
{
cout<<a3[i]<<" ";
}
}
//功能4
if (a3 == a1)
{
printf("\nequal\n");
}
else
{
printf("\nnot equal\n");
}
//a3.operator==(a1);
//bool operator==(Array &a1);
if (a3 != a1)
{
printf("\nnot equal\n");
}
else
{
printf("\nequal\n");
}
//
//a3.operator!=(a1)
// bool operator!=(Array &a1);
cout<<"hello..."<<endl;
return 1;
}
5.重载函数调用运算符
- () 运算符用于函数调用
- 重载格式
类型 类 :: operator() ( 表达式表 ) ;
- 只能用成员函数重载,不能用友元函数重载
例1
设 x 是类 X 的一个对象,则表达式
x ( arg1, arg2, … )
可被解释为
x . operator () (arg1, arg2, … )
案例:
- 例2:用重载()运算符实现数学函数的抽象
#include <iostream>
class F
{ public :
double operator ( ) ( double x , double y ) ;
} ;
double F :: operator ( ) ( double x , double y )
{ return x * x + y * y ; }
void main ( )
{
F f ;
f.getA();
cout << f ( 5.2 , 2.5 ) << endl ; // f . operator() (5.2, 2.5)
}
- 例3 用重载()运算符实现 pk 成员函数
#include <iostream.h>
class F
{ public :
double memFun ( double x , double y ) ;
} ;
double F :: memFun ( double x , double y )
{ return x * x + y * y ; }
void main ( )
{
F f ;
cout << f.memFun ( 5.2 , 2.5 ) << endl ;
}
6.不建议重载的运算符
理论知识:
1)&&和||是C++中非常特殊的操作符
2)&&和||内置实现了短路规则
3)操作符重载是靠函数重载来完成的
4)操作数作为函数参数传递
5)C++的函数参数都会被求值,无法实现短路规则
#include <cstdlib>
#include <iostream>
using namespace std;
class Test
{
int i;
public:
Test(int i)
{
this->i = i;
}
Test operator+ (const Test& obj)
{
Test ret(0);
cout<<"执行+号重载函数"<<endl;
ret.i = i + obj.i;
return ret;
}
bool operator&& (const Test& obj)
{
cout<<"执行&&重载函数"<<endl;
return i && obj.i;
}
};
// && 从左向右
void main()
{
int a1 = 0;
int a2 = 1;
cout<<"注意:&&操作符的结合顺序是从左向右"<<endl;
if( a1 && (a1 + a2) )
{
cout<<"有一个是假,则不在执行下一个表达式的计算"<<endl;
}
Test t1 = 0;
Test t2 = 1;
//if( t1 && (t1 + t2) )
//t1 && t1.operator+(t2)
// t1.operator&&( t1.operator+(t2) )
//1 && || 重载他们 不会产生短路效果
if( (t1 + t2) && t1)
{
//t1.operator+(t2) && t1;
//(t1.operator+(t2)).operator&&(t1);
cout<<"两个函数都被执行了,而且是先执行了+"<<endl;
}
//2 && 运算符的结合性
// 两个逻辑与运算符 在一块的时候, 采去谈 运算符的结合性
// 从左到右 (t1 + t2) && t1 ; 运算结果 && t2)
//if( (t1 + t2) && t1 && t2)
{
//t1.operator+(t2) && t1;
//(t1.operator+(t2)).operator&&(t1);
cout<<"两个函数都被执行了,而且是先执行了+"<<endl;
}
system("pause");
return ;
}
5.字符串类的实现
- 头文件
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
using namespace std;
#include <stdlib.h>
#include <string.h>
class MyString
{
public:
MyString();
MyString(int _len);
MyString(const char *_str);
MyString(const MyString & obj);
~MyString();
MyString& operator =(const MyString & obj);
MyString& operator =(const char * _str);
bool operator ==(const MyString & obj);
bool operator ==(const char * _str);
bool operator !=(const MyString & obj);
bool operator !=(const char * _str);
bool operator >(const MyString & obj);
bool operator >(const char * _str);
bool operator <(const MyString & obj);
bool operator <(const char * _str);
char& operator [](int index);
friend ostream& operator<<(ostream & out,MyString & obj);
friend istream& operator>>(istream & in,MyString & obj);
private:
int m_len;
char *m_str;
};
#endif // MYSTRING_H
- 实现文件
#include "mystring.h"
MyString::MyString()
{
m_len = 0;
m_str = NULL;
}
MyString::MyString(int _len)
{
if(_len < 0)
_len = 0;
m_len = _len;
m_str = new char[m_len+1];
memset(m_str,0,m_len);
}
MyString::MyString(const char *_str)
{
if(_str == NULL)
{
m_len = 0;
m_str = new char[m_len+1];
strcpy(m_str,"");
}else
{
m_len = strlen(_str);
m_str = new char[m_len+1];
strcpy(m_str,_str);
}
}
MyString::MyString(const MyString & obj)
{
m_len = obj.m_len;
m_str = new char[m_len+1];
strcpy(m_str,obj.m_str);
}
MyString::~MyString()
{
if(m_str != NULL)
{
delete []m_str;
m_str = NULL;
m_len = 0;
}
}
MyString& MyString::operator =(const MyString & obj)
{
if(m_str != NULL)
{
delete []m_str;
m_str = NULL;
m_len = 0;
}
m_len = obj.m_len;
m_str = new char[m_len+1];
strcpy(m_str,obj.m_str);
return *this;
}
MyString& MyString::operator =(const char * _str)
{
if(m_str != NULL)
{
delete []m_str;
m_str = NULL;
m_len = 0;
}
if(_str == NULL)
{
m_len = 0;
m_str = new char[m_len+1];
strcpy(m_str,"");
}else
{
m_len = strlen(_str);
m_str = new char[m_len+1];
strcpy(m_str,_str);
}
return *this;
}
bool MyString::operator ==(const MyString & obj)
{
if(m_len != obj.m_len)
{
return false;
}
return !strcmp(m_str,obj.m_str);
}
bool MyString::operator ==(const char * _str)
{
if(_str == NULL)
{
if(m_len == 0)
{
return true;
}else{
return false;
}
}else{
if(m_len == strlen(_str)){
return !strcmp(m_str,_str);
}else{
return false;
}
}
}
bool MyString::operator !=(const MyString & obj)
{
return !((*this) == obj);
}
bool MyString::operator !=(const char * _str)
{
return !((*this) == _str);
}
bool MyString::operator >(const MyString & obj)
{
if(strcmp(m_str,obj.m_str) > 0)
{
return true;
}else{
return false;
}
}
bool MyString::operator >(const char * _str)
{
if(strcmp(m_str,_str) > 0)
{
return true;
}else{
return false;
}
}
bool MyString::operator <(const MyString & obj)
{
if(strcmp(m_str,obj.m_str) < 0)
{
return true;
}else{
return false;
}
}
bool MyString::operator <(const char * _str)
{
if(strcmp(m_str,_str) < 0)
{
return true;
}else{
return false;
}
}
char& MyString::operator [](int index)
{
return m_str[index];
}
ostream& operator<<(ostream & out,MyString & obj)
{
out<<obj.m_str;
return out;
}
istream& operator>>(istream & in,MyString & obj)
{
in>>obj.m_str;
return in;
}
- 测试文件
#define _CRT_SECURE_NO_WARNINGS
#include "mystring.h"
void main01()
{
MyString s1;
MyString s2("s2");
MyString s2_2 = NULL;
MyString s3 = s2;
MyString s4 = "s4444444444";
//测试运算符重载 和 重载[]
//=
s4 = s2;
s4 = "s2222";
s4[1] = '4';
printf("%c", s4[1]);
cout<<s4 <<endl;
//ostream& operator<<(ostream &out, MyString &s)
//char& operator[] (int index)
//MyString& operator=(const char *p);
//MyString& operator=(const MyString &s);
cout<<"hello..."<<endl;
system("pause");
return ;
}
void main02()
{
MyString s1;
MyString s2("s2");
MyString s3 = s2;
if (s2 == "aa")
{
printf("相等");
}
else
{
printf("不相等");
}
if (s3 == s2)
{
printf("相等");
}
else
{
printf("不相等");
}
}
void main03()
{
MyString s1;
MyString s2("s2");
MyString s3 = s2;
s3 = "aaa";
if (s3 < "bbbb" )
{
printf("s3 小于 bbbb");
}
else
{
printf("s3 大于 bbbb");
}
MyString s4 = "aaaaffff";
//strcpy(s4.c_str(), "aa111"); //MFC
cout<<s4<<endl;
}
void main011()
{
MyString s1(128);
cout<<"\n请输入字符串(回车结束)";
cin>>s1;
cout<<s1;
system("pause");
}
int main()
{
MyString s1(128);
cout<<"\n请输入字符串(回车结束)";
cin>>s1;
cout<<s1<<endl;
system("pause");
return 0;
}
总结
- 操作符重载是C++的强大特性之一
- 操作符重载的本质是通过函数扩展操作符的语义
- operator关键字是操作符重载的关键
- friend关键字可以对函数或类开发访问权限
- 操作符重载遵循函数重载的规则
- 操作符重载可以直接使用类的成员函数实现
- =, [], ()和->操作符只能通过成员函数进行重载
- ++操作符通过一个int参数进行前置与后置的重载
- C++中不要重载&&和||操作符