C++运算符重载 模板友元 new delete ++ = +=
今天的重载是基于C++ 类模板的,如果需要非类模板的重载的朋友可以把类模板拿掉,同样可以参考,谢谢。
一、类模板中的友元重载
本人喜好类声明与类成员实现分开写的代码风格,如若您喜欢将类成员函数的实现写在类声明中,那么可以跳过该部分。
请看下面这段代码:
头文件:
#pragma once
template<typename T>
class CLA
{
T m_value;
public:
CLA(const T&);
friend CLA operator+(const CLA&, const CLA&);
};
template<typename T>
CLA<T>::CLA(const T& a)
:m_value(a)
{ } template<typename T>
CLA<T> operator+(const CLA<T>& lhs, const CLA<T>& rhs)
{
return CLA<T>(lhs.m_value + rhs.m_value);
}
源文件:(已包含上述的头文件)
int main()
{
CLA<int> a{ }, b{ }, c{ };
a + b;
return ;
}
我们去执行上述代码的时候,编译器就会报错:一个无法解析的外部指令。
当然,将实现放入声明中是可以的,但是为了维护类的书写风格,我们还是希望有一种方法可以去维护这个风格。
那么我们可以将类中友元函数的声明写成如下形式:
friend CLA operator+<T>(const CLA&, const CLA&);
原因很简单,类模板具有抽象性,而刚刚那个友元函数就是普通的函数,不具有模板的抽象性。
即使参数为CLA<T> ... 还是一样,它代表的只不过是一个参数的类型,函数本身依旧是一个普通的 函数。
而上述的形式更像一个函数模板,将函数的模板实参同步于类模板的参数,这样就可以作为类模板的友元了。
二、各种运算符重载
这部分我们将会说到 + - * / 关系运算符 赋值 自增自减 以及new delete 的重载。
首先,几个简单的 + - * / 友元以及非友元重载形式
#pragma once
#include<iostream>
using namespace std; template<typename T>
class CLA
{
T m_value;
public:
CLA():m_value(){}
CLA(const T&);
CLA(const CLA&);
//友元形式
friend CLA operator+<T>(const CLA&, const CLA&); //同类型
friend CLA operator+<T>(const CLA&, const T); //不同类型
friend CLA operator-<T>(const CLA&, const CLA&); //同类型
friend CLA operator-<T>(const CLA&, const T); //不同类型
//非友元形式
CLA operator*(const CLA&); //同类型
CLA operator*(const T); //不同类型
CLA operator/(const CLA&); //同类型
CLA operator/(const T); //不同类型
};
template<typename T>
CLA<T>::CLA(const T& a)
:m_value(a)
{ }
template<typename T>
CLA<T> operator+(const CLA<T>& lhs, const CLA<T>& rhs)
{
return CLA<T>(lhs.m_value + rhs.m_value);
}
template<typename T>
CLA<T> operator+(const CLA<T>& lhs, const T rhs)
{
return CLA<T>(lhs.m_value + rhs);
}
template<typename T>
CLA<T>::CLA(const CLA<T>& rhs)
: m_value(rhs.m_value)
{ } template<typename T>
CLA<T> operator-(const CLA<T>& lhs, const CLA<T>& rhs)
{
return CLA<T>(lhs.m_value - rhs.m_value);
}
template<typename T>
CLA<T> operator-(const CLA<T>& lhs, const T rhs)
{
return CLA<T>(lhs.m_value - rhs);
}
template<typename T>
CLA<T> CLA<T>::operator*(const CLA<T>& rhs)
{
return CLA<T>(m_value * rhs.m_value);
}
template<typename T>
CLA<T> CLA<T>::operator*(const T rhs)
{
return CLA<T>(m_value * rhs);
}
template<typename T>
CLA<T> CLA<T>::operator/(const CLA<T>& rhs)
{
if (rhs.m_value)
return CLA<T>(m_value / rhs.m_value);
else
cout << "非法除法!" << endl;
return CLA<T>();
}
template<typename T>
CLA<T> CLA<T>::operator/(const T rhs)
{
if (rhs)
return CLA<T>(lhs.m_value / rhs);
else
cout << "非法除法!" << endl;
return CLA<T>();
}
接下来重载输入输出流,而且必须为友元才行
friend istream& operator>> <T>(istream&, CLA&);
friend ostream& operator<< <T>(ostream&, const CLA&);
istream& operator>>(istream& is, CLA<T>& rhs)
{
is >> rhs.m_value;
return is;
}
template<typename T>
ostream& operator<<(ostream& os, const CLA<T>& rhs)
{
os << rhs.m_value;
return os;
}
输入流重载的第二个参数不能为const,因为在函数体中要对之进行修改
然后,我们用下面的代码来看一下测试结果:
int main()
{
CLA<int> a{ }, b{ }, c{ };
CLA<char> B{ 'b' };
b / a; //相同类型
cout << b*c << endl; //相同类型
cout << B + (char) << endl; //不同类型的
cout << B - (char) << endl; //不同类型的
return 0;
}
没有问题
接下类重载一些赋值运算符,= += -=
CLA& operator=(const CLA&);
CLA& operator+=(const CLA&);
CLA& operator-=(const CLA&);
CLA<T>& CLA<T>::operator=(const CLA<T>& rhs)
{
if (this != &rhs)
m_value = rhs.m_value;
return *this;
}
template<typename T>
CLA<T>& CLA<T>::operator+=(const CLA<T>& rhs)
{
m_value += rhs.m_value;
return *this;
}
template<typename T>
CLA<T>& CLA<T>::operator-=(const CLA<T>& rhs)
{
m_value -= rhs.m_value;
return *this;
}
赋值号要记得要有判同语句,运算完成后要将*this,也就是操作符的左操作数,返回。
这部分之后进行测试
++重载(--雷同)
CLA& operator++(); //前++
const CLA operator++(int); //后++
CLA<T>& CLA<T>::operator++()
{
++m_value;
return *this;
}
template<typename T>
const CLA<T> CLA<T>::operator++(int) //语法规定,在后++函数的参数中加int以作区分
{
CLA<T> item(m_value);
++m_value;
return item;
}
根据前++和后++的语法规则,前++,将本身的值+1,然后再将其本身返回。如上述操作函数体语句所示。
而后++则是将原值返回,然后本身+1,所以,我们需要借助一个局部变量来保存原值,而且返回之后是不允许改变的,代表一个常量,所以返回值拥有const属性
关系运算符也挺简单的
friend bool operator!= <T>(const CLA&, const CLA&);//友元
bool operator!=(const CLA&); //成员函数
bool operator==(const CLA&);
bool operator<(const CLA&);
bool operator>=(const CLA&);
template<typename T>
bool operator!=(const CLA<T>& lhs, const CLA<T>& rhs)
{
return lhs.m_value != rhs.m_value;
}
bool CLA<T>::operator!=(const CLA<T> & rhs)
{
return this->m_value != rhs.m_value;
}
template<typename T>
bool CLA<T>::operator==(const CLA<T>& rhs)
{
return m_value == rhs.m_value;
}
template<typename T>
bool CLA<T>::operator<(const CLA<T>& rhs)
{
return m_value < rhs.m_value;
}
template<typename T>
bool CLA<T>::operator>=(const CLA<T>& rhs)
{
return m_value > rhs.m_value;
}
我们来测试一下
int main()
{ CLA<int> a{ }, b{ }, c{ };
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 += ) << endl;
cout << (r < a) << endl; return ;
}
忘了写连续赋值,不过,经测试也是可以的,没问题 。
那么,现在我们来重载 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<typename T>
void* CLA<T>::operator new(size_t size)
{
cout << size << endl;
cout << "调用了new" << endl;
return malloc(size);
}
template<typename T>
void* CLA<T>::operator new[](size_t size)
{
cout << size << endl;
cout << "调用了new[]" << endl;
return malloc(size);
}
template<typename T>
void CLA<T>::operator delete(void* p)
{
free(p);
cout << "调用了delete函数" << endl;
}
template<typename T>
void CLA<T>::operator delete[](void* p)
{
free(p);
cout << "调用了delete[]函数" << endl;
}
我们写一些对应的输出来帮助我们确定一些信息。
int main()
{
CLA<int>* w = new CLA<int>();
delete w;
CLA<int>* W = new CLA<int>[];
delete[] W;
return ;
}
第一个10为创建的对象的值,第二个为开辟的数组的大小
一个int为4个字节,开辟10个大小的内存,为40个字节,没有问题
类模板的运算符重载就到这里了
感谢您的阅读,祝您生活愉快!
C++运算符重载 模板友元 new delete ++ = +=的更多相关文章
- c++入门之—运算符重载和友元函数
运算符重载的意义是:将常见的运算符重载出其他的含义:比如将*重载出指针的含义,将<<与cout联合使用重载出输出的含义,但需要认识到的问题是:运算符的重载:本质仍然是成员函数,即你可以认为 ...
- C++抽象编程·运算符重载与友元函数
运算符重载(Operator overloading) 从我们在几个前篇的类的层次介绍中可以知道,C++可以扩展标准运算符,使其适用于新类型.这种技术称为运算符重载. 例如,字符串类重载+运算符,使其 ...
- CPP_运算符重载及友元
运算符重载 两种重载方法1)成员函数 a + b => a.operator+(b); 一个参数 2)友元函数 a + b => operator+(a, b); 两个参数. friend ...
- C++运算符重载(友元函数方式)
我们知道,C++中的运算符重载有两种形式:①重载为类的成员函数(见C++运算符重载(成员函数方式)),②重载为类的友元函数. 当重载友元函数时,将没有隐含的参数this指针.这样,对双目运算符,友元函 ...
- 运算符重载之new与delete
关于new/delete,援引C++ Primer中的一段话: 某些应用程序对内存分配有特殊的要求,因此我们无法直接将标准的内存管理机制直接应用于这些程序.他们常常需要自定义内存分配的细节,比如使用关 ...
- 我的c++学习(8)运算符重载和友元
运算符的重载,实际是一种特殊的函数重载,必须定义一个函数,并告诉C++编译器,当遇到该运算符时就调用此函数来行使运算符功能.这个函数叫做运算符重载函数(常为类的成员函数). 方法与解释 ◆ 1.定义运 ...
- 从零开始学C++之运算符重载(三):完善String类([]、 +、 += 运算符重载)、>>和<<运算符重载
在前面文章中使用过几次String类的例子,现在多重载几个运算符,更加完善一下,并且重载流类运算符. []运算符重载 +运算符重载 +=运算符重载 <<运算符重载 >>运算符重 ...
- 完善String类([]、 +、 += 运算符重载)、>>和<<运算符重载
在前面文章中使用过几次String类的例子,现在多重载几个运算符,更加完善一下,并且重载流类运算符. []运算符重载 +运算符重载 +=运算符重载 <<运算符重载 >>运算符重 ...
- 新标准C++程序设计读书笔记_运算符重载
形式 返回值类型 operator 运算符(形参表) { …… } 运算符重载 (1)运算符重载的实质是函数重载(2)可以重载为普通函数,也可以重载为成员函数 class Complex { publ ...
随机推荐
- LintCode 388: Kth Permutation
LintCode 388: Kth Permutation 题目描述 给定 n 和 k,求123..n组成的排列中的第 k 个排列. 样例 对于 n = 3, 所有的排列如下: 123 132 213 ...
- Codeforces刷题计划
Codeforces刷题计划 已完成:-- / -- [Codeforces370E]370E - Summer Reading:构造:(给定某些数,在空白处填数,要求不下降,并且相邻差值<=1 ...
- OI刷题录——hahalidaxin
16-3-25 —— bzoj 2049 [Sdoi2008]Cave 洞穴勘测:LCT入门 bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊:LCT Tsinsen A1303. t ...
- 20155233 2016-2017-2 《Java程序设计》第6周学习总结
20155233 2016-2017-2 <Java程序设计>第6周学习总结 学习目标 理解流与IO 理解InputStream/OutPutStream的继承架构 理解Reader/Wr ...
- [HNOI2008]越狱 题解(容斥原理+快速幂)
[HNOI2008]越狱 Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多 ...
- 【bzoj题解】1001 狼抓兔子
题目描述 现在小朋友们最喜欢"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: ...
- java 压缩与解压
最近复习到IO,想找个案例做一做,恰好下载了许多图片压缩包,查看图片很不方便,所以打算用IO把图片都解压到同一个文件夹下.然后集中打包. 本例使用jdk自带的ZipInputStream和ZipOut ...
- 阿里面试回来,想和Java程序员谈一谈
引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...
- 【API】Mysql UDF BackDoor
1.MySQL UDF是什么 UDF是Mysql提供给用户实现自己功能的一个接口,为了使UDF机制起作用,函数必须用C或C ++编写,并且操作系统必须支持动态加载.这篇文章主要介绍UDF开发和利用的方 ...
- python进阶之类常用魔法方法和魔法属性
前言 前面我们总结过了python的关键字.运算符.内置函数.语法糖等与python魔法方法之间的关系,现在我们更细一点,看看python的面向对象编程有哪些常用的魔法属性和魔法方法. 魔法属性 对于 ...