转 C++运算符重载 模板友元 new delete ++ = +=

C++运算符重载 模板友元 new delete ++ = +=
https://www.cnblogs.com/lv-anchoret/p/8342842.html
今天的重载是基于C++ 类模板的,如果需要非类模板的重载的朋友可以把类模板拿掉,同样可以参考,谢谢。

一、类模板中的友元重载

本人喜好类声明与类成员实现分开写的代码风格,如若您喜欢将类成员函数的实现写在类声明中,那么可以跳过该部分。

请看下面这段代码:

头文件:

复制代码
#pragma once
template
class CLA
{
T m_value;
public:
CLA(const T&);
friend CLA operator+(const CLA&, const CLA&);
};
template
CLA::CLA(const T& a)
:m_value(a)
{ }

template
CLA operator+(const CLA& lhs, const CLA& rhs)
{
return CLA(lhs.m_value + rhs.m_value);
}
复制代码
源文件:(已包含上述的头文件)

int main()
{
CLA a{ 0 }, b{ 1 }, c{ 2 };
a + b;
return 0;
}
我们去执行上述代码的时候,编译器就会报错:一个无法解析的外部指令。

当然,将实现放入声明中是可以的,但是为了维护类的书写风格,我们还是希望有一种方法可以去维护这个风格。

那么我们可以将类中友元函数的声明写成如下形式:

friend CLA operator+(const CLA&, const CLA&);

原因很简单,类模板具有抽象性,而刚刚那个友元函数就是普通的函数,不具有模板的抽象性。

即使参数为CLA … 还是一样,它代表的只不过是一个参数的类型,函数本身依旧是一个普通的 函数。

而上述的形式更像一个函数模板,将函数的模板实参同步于类模板的参数,这样就可以作为类模板的友元了。

二、各种运算符重载

这部分我们将会说到 + - * / 关系运算符 赋值 自增自减 以及new delete 的重载。

首先,几个简单的 + - * / 友元以及非友元重载形式

复制代码
#pragma once
#include
using namespace std;

template
class CLA
{
T m_value;
public:
CLA():m_value(0){}
CLA(const T&);
CLA(const CLA&);
//友元形式
friend CLA operator+(const CLA&, const CLA&); //同类型
friend CLA operator+(const CLA&, const T); //不同类型
friend CLA operator-(const CLA&, const CLA&); //同类型
friend CLA operator-(const CLA&, const T); //不同类型
//非友元形式
CLA operator*(const CLA&); //同类型
CLA operator*(const T); //不同类型
CLA operator/(const CLA&); //同类型
CLA operator/(const T); //不同类型
};
template
CLA::CLA(const T& a)
:m_value(a)
{ }
template
CLA operator+(const CLA& lhs, const CLA& rhs)
{
return CLA(lhs.m_value + rhs.m_value);
}
template
CLA operator+(const CLA& lhs, const T rhs)
{
return CLA(lhs.m_value + rhs);
}
template
CLA::CLA(const CLA& rhs)
: m_value(rhs.m_value)
{ }

template
CLA operator-(const CLA& lhs, const CLA& rhs)
{
return CLA(lhs.m_value - rhs.m_value);
}
template
CLA operator-(const CLA& lhs, const T rhs)
{
return CLA(lhs.m_value - rhs);
}
template
CLA CLA::operator*(const CLA& rhs)
{
return CLA(m_value * rhs.m_value);
}
template
CLA CLA::operator*(const T rhs)
{
return CLA(m_value * rhs);
}
template
CLA CLA::operator/(const CLA& rhs)
{
if (rhs.m_value)
return CLA(m_value / rhs.m_value);
else
cout << “非法除法!” << endl;
return CLA();
}
template
CLA CLA::operator/(const T rhs)
{
if (rhs)
return CLA(lhs.m_value / rhs);
else
cout << “非法除法!” << endl;
return CLA();
}
复制代码

接下来重载输入输出流,而且必须为友元才行

friend istream& operator>> (istream&, CLA&);
friend ostream& operator<< (ostream&, const CLA&);
复制代码
istream& operator>>(istream& is, CLA& rhs)
{
is >> rhs.m_value;
return is;
}
template
ostream& operator<<(ostream& os, const CLA& rhs)
{
os << rhs.m_value;
return os;
}
复制代码
输入流重载的第二个参数不能为const,因为在函数体中要对之进行修改

然后,我们用下面的代码来看一下测试结果:

复制代码
int main()
{
CLA a{ 0 }, b{ 1 }, c{ 2 };
CLA B{ ‘b’ };
b / a; //相同类型
cout << b*c << endl; //相同类型
cout << B + (char)1 << endl; //不同类型的
cout << B - (char)1 << endl; //不同类型的
return 0;
}
复制代码

没有问题

接下类重载一些赋值运算符,= += -=

CLA& operator=(const CLA&);
CLA& operator+=(const CLA&);
CLA& operator-=(const CLA&);
复制代码
CLA& CLA::operator=(const CLA& rhs)
{
if (this != &rhs)
m_value = rhs.m_value;
return *this;
}
template
CLA& CLA::operator+=(const CLA& rhs)
{
m_value += rhs.m_value;
return *this;
}
template
CLA& CLA::operator-=(const CLA& rhs)
{
m_value -= rhs.m_value;
return this;
}
复制代码
赋值号要记得要有判同语句,运算完成后要将
this,也就是操作符的左操作数,返回。

这部分之后进行测试

++重载(–雷同)

CLA& operator++(); //前++
const CLA operator++(int); //后++
复制代码
CLA& CLA::operator++()
{
++m_value;
return *this;
}
template
const CLA CLA::operator++(int) //语法规定,在后++函数的参数中加int以作区分
{
CLA item(m_value);
++m_value;
return item;
}
复制代码
根据前++和后++的语法规则,前++,将本身的值+1,然后再将其本身返回。如上述操作函数体语句所示。

而后++则是将原值返回,然后本身+1,所以,我们需要借助一个局部变量来保存原值,而且返回之后是不允许改变的,代表一个常量,所以返回值拥有const属性

关系运算符也挺简单的

friend bool operator!= (const CLA&, const CLA&);//友元
bool operator!=(const CLA&); //成员函数
bool operator==(const CLA&);
bool operator<(const CLA&);
bool operator>=(const CLA&);
复制代码
template
bool operator!=(const CLA& lhs, const CLA& rhs)
{
return lhs.m_value != rhs.m_value;
}
bool CLA::operator!=(const CLA & rhs)
{
return this->m_value != rhs.m_value;
}
template
bool CLA::operator==(const CLA& rhs)
{
return m_value == rhs.m_value;
}
template
bool CLA::operator<(const CLA& rhs)
{
return m_value < rhs.m_value;
}
template
bool CLA::operator>=(const CLA& rhs)
{
return m_value > rhs.m_value;
}
复制代码

我们来测试一下

复制代码
int main()
{

CLA<int> a{ 0 }, b{ 1 }, c{ 2 };
if (a != b)
    cout << "a!=b" << endl;
a++;
if (a == b)
    cout << "a==b" << endl;

//c++++             //Invalid !!
CLA<int> r = ++++a;
cout << r << endl;
cout << (r += 1) << endl;
cout << (r < a) << endl;

    return 0;

}
复制代码

忘了写连续赋值,不过,经测试也是可以的,没问题 。

那么,现在我们来重载 new 和delete 以及new [ ] 和 delete [ ]

void* operator new(size_t size);
void* operator new[](size_t size);
void operator delete(void* p);
void operator delete[](void* p);
这里我们要用到的一个C语言库里面的类型—— size_t,它是unsigned int,sizeof运算符算出来的值就是它喽,在这里作为参数,它会自动计算大小,很方便

那,我们来看一下它的实现:

复制代码
template
void* CLA::operator new(size_t size)
{
cout << size << endl;
cout << “调用了new” << endl;
return malloc(size);
}
template
void* CLA::operator new[](size_t size)
{
cout << size << endl;
cout << “调用了new[]” << endl;
return malloc(size);
}
template
void CLA::operator delete(void* p)
{
free§;
cout << “调用了delete函数” << endl;
}
template
void CLA::operator delete[](void* p)
{
free§;
cout << “调用了delete[]函数” << endl;
}
复制代码
我们写一些对应的输出来帮助我们确定一些信息。

复制代码
int main()
{
CLA* w = new CLA(10);
delete w;
CLA* W = new CLA[10];
delete[] W;
return 0;
}
复制代码

第一个10为创建的对象的值,第二个为开辟的数组的大小

一个int为4个字节,开辟10个大小的内存,为40个字节,没有问题

类模板的运算符重载就到这里了

感谢您的阅读,祝您生活愉快!

作者:林-兮
    
出处:http://www.cnblogs.com/lv-anchoret/
    
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值