C++中符号(运算符)重载

12 篇文章 2 订阅
7 篇文章 0 订阅

全局函数与成员函数:
1、把全局函数转化成成员函数,通过this指针隐藏左操作数
Test add(Test &t1, Test &t2)=》Test add(Test &t2)
2、把成员函数转换成全局函数,多了一个参数
void printAB()
=》void printAB(Test *pthis)
3、函数返回元素和返回引用
Test& add(Test &t2) //*this //函数返回引用
{
this->a = this->a + t2.getA();
this->b = this->b + t2.getB();
return *this; //*操作让this指针回到元素状态
}

            Test add2(Test &t2) //*this //函数返回元素
            {
                  //t3是局部变量
                  Test t3(this->a+t2.getA(), this->b + t2.getB()) ;
                  return t3;
            }

#include
using namespace std;

class Test
{
public:
int a;
int b;

public:
~Test()
{
cout<<“a:”<<a<<" b: "<<b;
cout<<“析构函数自动被调用”<<endl;
}

public:
void printT()
{
cout<<“a:”<<a<<" b: "<<b<<endl;
}

public:
//t3 = t1.TestAdd(t2);
Test TestAdd(Test &t2)
{
Test tmp(this->a + t2.a, this->b + t2.b);
return tmp;
}

//t1.TestAdd2(t2);
//返回一个引用 相当于返回自身
//返回t1这个元素 this就是&t1
Test& TestAdd2(Test &t2)
{
    this->a = this->a + t2.a;
    this->b = this->b + t2.b;

    return *this; //把 *(&t1) 又回到了 t1元素
}

public:
Test(int a=0, int b=0)
{
this->a = a;
this->b = b;
}
};

//把成员函数 转成 全局函数 多了一个参数
void printT(Test *pT)
{
cout<<“a:”<a<<" b: "<b<<endl;
}

//全局函数的方法
//全局函数 转成 成员函数 少了一个参数
Test TestAdd(Test &t1, Test &t2)
{
Test tmp;
return tmp;
}

void main()
{
Test t1(1, 2);
Test t2(3, 4);

//t1 = t1 + t2 + t2;
t1.TestAdd2(t2).TestAdd2(t2);
t1.printT();

}

void main1()
{
Test t1(1, 2);
Test t2(3, 4);

Test t3 ;

//全局函数方法
t3 = TestAdd(t1, t2);
//成员函数方法
{
    //先把测试案例写出来
    Test t4 = t1.TestAdd(t2); //匿名对象直接转化成t4
    t4.printT();
    Test t5;
    t5 = t1.TestAdd(t2); //匿名对象 复制 给t5
    t5.printT();
}


cout<<"hello..."<<endl;
system("pause");
return ;

}
#include
using namespace std;

class Test
{
public:
int a;
int b;

public:
~Test()
{
cout<<“a:”<<a<<" b: "<<b;
cout<<“析构函数自动被调用”<<endl;
}

public:
void printT()
{
cout<<“a:”<<a<<" b: "<<b<<endl;
}

public:
//t3 = t1.TestAdd(t2);
Test TestAdd(Test &t2)
{
Test tmp(this->a + t2.a, this->b + t2.b);
return tmp;
}

//t1.TestAdd2(t2);
//返回一个引用 相当于返回自身
//返回t1这个元素 this就是&t1
Test& TestAdd2(Test &t2)
{
    this->a = this->a + t2.a;
    this->b = this->b + t2.b;

    return *this; //把 *(&t1) 又回到了 t1元素
}

public:
Test(int a=0, int b=0)
{
this->a = a;
this->b = b;
}
};

//把成员函数 转成 全局函数 多了一个参数
void printT(Test *pT)
{
cout<<“a:”<a<<" b: "<b<<endl;
}

//全局函数的方法
//全局函数 转成 成员函数 少了一个参数
Test TestAdd(Test &t1, Test &t2)
{
Test tmp;
return tmp;
}

void main()
{
Test t1(1, 2);
Test t2(3, 4);

//t1 = t1 + t2 + t2;
t1.TestAdd2(t2).TestAdd2(t2);
t1.printT();

}

void main1()
{
Test t1(1, 2);
Test t2(3, 4);

Test t3 ;

//全局函数方法
t3 = TestAdd(t1, t2);
//成员函数方法
{
    //先把测试案例写出来
    Test t4 = t1.TestAdd(t2); //匿名对象直接转化成t4
    t4.printT();
    Test t5;
    t5 = t1.TestAdd(t2); //匿名对象 复制 给t5
    t5.printT();
}


cout<<"hello..."<<endl;
system("pause");
return ;

}

友元函数:
友元函数不是类的内部函数,是一个全局函数,但是可以改变类的私有属性
友元函破坏了类的封装性.
class Test
{
public:
// 友元函数的声明与位置、public、private等都无关
// 友元函数不是类的内部函数,是一个全局的函数
friend void test(Test *pTest);
Test(int a, int b)
{
this->a = a;
this->b = b;
}

int getA()
{
    return this->a;
}

private:

int a;
int b;

};

小结:
1.类通常用关键字class定义。类是数据成员和成员函数的封装。类的实例称为对象。

2.结构类型用关键字struct定义,是由不同类型数据组成的数据类型。

3 类成员由private, protected, public决定访问特性。public成员集称为接口。

4.构造函数在创建和初始化对象时自动调用。析构函数则在对象作用域结束时自动调用。

5.重载构造函数和复制构造函数提供了创建对象的不同初始化方式。

6 静态成员是局部于类的成员,提供一种同类对象的共享机制。

7.友员用关键字friend声明。友员是对类操作的一种辅助手段。一个类的友员可以访问该类各种性质的成员。

8.链表是一种重要的动态数据结构,可以在程序运行时创建或撤消数据元素**

下面正式介绍运算符重载:
所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。

运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。例如,大 家都已习惯于用加法运算符”+”对整数、单精度数和双精度数进行加法运算,如5+8, 5.8 +3.67等。
1为什么会用运算符重载机制
用复数类举例
Complex c3 = c1 + c2;
原因 Complex是用户自定义类型,编译器根本不知道如何进行加减
编译器给提供了一种机制,让用户自己去完成,自定义类型的加减操作。。。。。
这个机制就是运算符重载机制
2 运算符重载的本质是一个函数
#include
using namespace std;

class Complex
{
public:
int a;
int b;
public:
Complex(int a=0, int b=0)
{
this->a = a;
this->b = b;
}
void printCom()
{
cout<<a<<" + " << b << “i” <<endl;
}
};

//1 定义了全局函数
Complex myAdd(Complex &c1, Complex &c2)
{
Complex tmp(c1.a + c2.a, c1.b+ c2.b);
return tmp; //
}

//2 函数名 升级
Complex operator+(Complex &c1, Complex &c2)
{
cout<<“12345上山 打老虎”<<endl;
Complex tmp(c1.a + c2.a, c1.b+ c2.b);
return tmp; //
}

int main()
{
int a = 0, b = 0;
int c;
c = a + b; //1 基础数据类型 编译器已经知道了. 如何运算

// a + bi 复数运算规则
Complex c1(1, 2), c2(3, 4);
Complex c3; //2 类 也是一种数据类型  用户自定义数据类型 C++编译器 是不知道如何进行运算
//c3 = c1 + c2 ;
//c1--; --c1

//3 c++编译器应该给我们程序员提供一种机制 ...
//让自定义数据类型 有机会 进行 运算符操作 ====> 运算符重载机制

//4 运算符重载机制

//步骤1
//Complex c4 = myAdd(c1, c2);
//c4.printCom();

//步骤2  //Complex c4  = c1 + c2
//Complex c4 = operator+(c1, c2);
//c4.printCom();

//步骤3
Complex c4 = c1 + c2;
c4.printCom();

//步骤3
Complex c4 = c1 / c2;
c4.printCom();

//总结: 1 运算符重载的本质 是 函数调用

cout<<"hello..."<<endl;
return 0;

}
不能重载的运算符有:
. :: .
?: sizeof
x++=1; //后置不能作为左值,重载后置不能返回引用。返回常量。后置++需要占位参数。
++x=1; //前置++可以作为左值,重载前置++能返回引用。
=,[ ],(),->等操作符只能重载为成员函数,不能重载为全局函数。
运算符函数可以重载为成员函数或友元函数。
*
关键在于成员函数具有this指针。友元函数没有this指针。
不管是成员函数还是友元函数,运算符使用方法相同。但传递的方式不同,实现的代码不同。

//前置++操作符 用全局函数实现
Complex& operator++(Complex &c1)
{
c1.a ++;
c1.b ++;
return c1;
}
//调用方法
++c1 ; //=è需要写出操作符重载函数原形
c1.printCom();

//运算符重载函数名定义
//首先承认操作符重载是一个函数 定义函数名èoperator++
//分析函数参数 根据左右操作数的个数,èoperator++(Complex &c1)
//分析函数返回值è Complex& operator++(Complex &c1) 返回它自身
//前置++操作符 用全局函数实现
例如4
//4.1前置—操作符 成员函数实现
Complex& operator–()
{
this->a–;
this->b–;
return *this;
}

  //4.2调用方法
       --c1;
       c1.printCom();
  //4.3前置—运算符重载函数名定义
  //c1.operator--()

例如5
//5.1 //后置++ 操作符 用全局函数实现
Complex operator++(Complex &c1, int)
{
Complex tmp = c1;
c1.a++;
c1.b++;
return tmp;
}
//5.2 调用方法
c1 ++ ; //先使用 后++
//5.3 后置++运算符重载函数名定义
Complex operator++(Complex &c1, int) //函数占位参数 和 前置++ 相区别
//6.2 调用方法
c1 ++ ; //先使用 后++
//6.3 后置–运算符重载函数名定义
Complex operator–(int) //函数占位参数 和 前置-- 相区别

前置和后置运算符总结
C++中通过一个占位参数来区分前置运算和后置运算
全局函数和类成员函数实现运算符重载的步骤:
1)要承认操作符重载是一个函数,写出函数名称operator+ ()
2)根据操作数,写出函数参数
3)根据业务,完善函数返回值(看函数是返回引用 还是指针 元素),及实现函数业务

用友元函数重载<<>>运算符:
istream 和 ostream 是 C++ 的预定义流类
cin 是 istream 的对象,cout 是 ostream 的对象
运算符 << 由ostream 重载为插入操作,用于输出基本类型数据
运算符 >> 由 istream 重载为提取操作,用于输入基本类型数据
用友员函数重载 << 和 >> ,输出和输入用户自定义的数据类型

用全局函数实现<<运算符:
ostream& operator<<(ostream &out, Complex &c1)
{
//out<<“12345,生活真是苦”<<endl;
out<<c1.a<<" + "<<c1.b<<"i "<<endl;
return out;
}
//调用方法
cout<<c1;
//链式编程支持
cout<<c1<<“abcc”;
//cout.operator<<(c1).operator<<(“abcd”);
//函数返回值充当左值 需要返回一个引用

#include
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;
}

int main()
{
objplaymain();
cout<<“hello…”<<endl;

return 0;
}
为什么不能重载&&和||运算符:
)&&和||是C++中非常特殊的操作符
2)&&和||内置实现了短路规则
3)操作符重载是靠函数重载来完成的
4)操作数作为函数参数传递
5)C++的函数参数都会被求值,无法实现短路规则
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;
}

};

// && 从左向右
int 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;
}

return 0;

}

运算符重载应用
实现字符串类:
.h文件:
#ifndef MYSTRING_H
#define MYSTRING_H

#include
using namespace std;

class MyString
{
friend ostream & operator<<(ostream& out, const MyString& str);
friend istream & operator>>(istream& in, const MyString& str);
public:
MyString(int len=0);
MyString(const char *p);
MyString(const MyString & str);
~MyString();

public:
MyString& operator=(const char *p);
MyString& operator=(const MyString &str);

char& operator[](const int index);

bool operator==(const char *p) const;
bool operator==(const MyString& str) const;
bool operator!=(const char *p) const;
bool operator!=(const MyString& str) const;

bool operator<(const char *p) const;
bool operator<(const MyString& str) const;
bool operator>(const char *p) const;
bool operator>(const MyString& str) const;

public:
char *c_str()
{
return m_p;
}
const char *c_str2()
{
return m_p;
}

int length()
{
    return m_len;
}

private:
int m_len;
char *m_p;
};

#endif

.cpp文件:
#include “MyString.h”
#include <string.h>

ostream & operator<<(ostream& out, const MyString& str)
{
out << str.m_p;
return out;
}

istream & operator>>(istream& in, const MyString& str)
{
in >> str.m_p;
return in;
}

MyString::MyString(int len)
{
if (len == 0)
{
m_len = 0;
m_p = new char[m_len + 1];
strcpy(m_p, “”);
}
else
{
m_len = len;
m_p = new char[m_len + 1];
memset(m_p, 0, m_len+1);
}
}

MyString::MyString(const char *p)
{
if (p == NULL)
{
m_len = 0;
m_p = new char[m_len + 1];
strcpy(m_p, “”);
}
else
{
m_len = strlen§;
m_p = new char[m_len + 1];
strcpy(m_p, p);
}

}

MyString::MyString(const MyString &str)
{
m_len = str.m_len;
m_p = new char[m_len + 1];
strcpy(m_p, str.m_p);
}

MyString::~MyString()
{
if (m_p != NULL)
{
delete [] m_p;
m_p = NULL;
m_len = 0;
}
}

MyString& MyString::operator=(const char *p)
{
if (m_p != NULL)
{
delete [] m_p;
}
if (p == NULL)
{
m_len = 0;
m_p = new char[m_len + 1];
strcpy(m_p, “”);
}
else
{
m_len = strlen§;
m_p = new char[m_len + 1];
strcpy(m_p, p);
}

return *this;

}

MyString& MyString::operator=(const MyString &str)
{
if (m_p != NULL)
{
delete [] m_p;
}

m_len = str.m_len;
m_p = new char[m_len + 1];
strcpy(m_p, str.m_p);

return *this;

}

char& MyString::operator[](const int index)
{
return m_p[index];
}

bool MyString::operator==(const char *p) const
{
if (p == NULL)
{
if (m_len == 0)
return true;
else
return false;
}
else
{
return !strcmp(m_p, p);
}
}

bool MyString::operator==(const MyString& str) const
{
return !strcmp(m_p, str.m_p);
}

bool MyString::operator!=(const char *p) const
{
return !(*this == p);
}

bool MyString::operator!=(const MyString& str) const
{
return !(*this == str);
}

bool MyString::operator<(const char *p) const
{
return (strcmp(m_p, p) < 0);
}

bool MyString::operator<(const MyString& str) const
{
return (strcmp(m_p, str.m_p) < 0);
}

bool MyString::operator>(const char *p) const
{
return (strcmp(m_p, p) > 0);;
}

bool MyString::operator>(const MyString& str) const
{
return (strcmp(m_p, str.m_p) > 0);
}
main.cpp文件:
int main1()
{
MyString s1;
MyString s2(“s2”);
MyString s2_2 = NULL;
MyString s3 = s2;

MyString s4 = "s42323233";
s4 = s2;
s4 = "headad";

cout << s4[2] << endl;

cout << s4 << endl;

return 0;

}

int main2()
{
MyString s1;
MyString s2(“s2”);
MyString s3(“s223123”);

if (s2 == NULL)
{
    cout << "相等" << endl;
}
else
{
    cout << "不相等" << endl;
}

if (s2 == s3)
{
    cout << "相等" << endl;
}
else
{
    cout << "不相等" << endl;
}


return 0;

}

int main3()
{
MyString s1;
MyString s2(“s2”);
MyString s3(“s3”);

if (s3 < "bbbb")
{
    cout << "s3 < bbbb" << endl;
}
else
{
    cout << "s3 > bbbb" << endl;
}

if (s3 > s2 )
{
    cout << "s3 > s2" << endl;
}
else
{
    cout << "s3 < s2" << endl;
}

return 0;

}

int main()
{
MyString s1(128);
cin >> s1;

cout << s1 << endl;

return 0;

}
操作符重载的总结:
操作符重载是C++的强大特性之一
操作符重载的本质是通过函数扩展操作符的语义
operator关键字是操作符重载的关键
friend关键字可以对函数或类开发访问权限
操作符重载遵循函数重载的规则
操作符重载可以直接使用类的成员函数实现
=, [], ()和->操作符只能通过成员函数进行重载
++操作符通过一个int参数进行前置与后置的重载
C++中不要重载&&和||操作符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值