C++
C重载
输入和输出只能用有元方式
重载>>
friend istream& operator>>(istream& is,Date& d);
ostream& operator<<(ostream& os,const Date& d){
return os << d.year << "-" << d.mon << "-" << d.day;
}
重载<<
friend ostream& operator<<(ostream& os,const Date& d);
istream& operator>>(istream& is,Date& d){
return is >> d.year >> d.mon >> d.day;
}
重载++ 有前++ 后++
Date& operator++(void){
++;
return *this;
}
Date operator++(int){
Date d(*this);
++(*this);//调用前++
return d;
}
重载-- 有前-- 后–
这里我们使用友元方式
friend Date& operator--(Date& d);
friend Date operator--(Date& d,int);
Date& operator--(Date& d){
--;
return d;
}
Date operator--(Date& d,int){
Date old(d);
--d;
return old;
}
重载比较运算符(关系运算符)
重载<和>
例如在比较日期环节,我们要从年月日一同比较,这个时候重载小于符号就比较方便
bool operator<(const Date& d)const{
if(year!=d.year)
return year < d.year;
if(mon!=d.mon)
return mon < d.mon;
return day < d.day;//
}
重载<=和>=
bool operator<=(const Date& d)const{
if(year!=d.year)
return year < d.year;
if(mon!=d.mon)
return mon < d.mon;
return day <= d.day;
}
一般来讲,只要定义一个<就行,因为>只是调用>
bool operator>(const Date& d)const{//*this > d
return d < *this;// d.operator<(*this);
}
bool operator>=(const Date& d)const{
return d <= *this; //d.operator<=(*this);
}
重载==和!=
bool operator==(const Date& d)const{
return year==d.year && mon==d.mon && day==d.day;
}
bool operator!=(const Date& d)const{
return !(*this==d);
}
sort(arr,arr+5);//排序函数在使用时会调用到<等比较符号,所以日期格式也能比较,sort函数是两个指针
//这里我们定义一个比较函数,这里重载定义了()
#include <algorithm>
class DateDesc{
public:
bool operator()(const Date& d1,const Date& d2){
return d2<d1;
}
};
sort(ds,ds+5,DateDesc());//C++不用函数指针,直接重载()使用函数对象
重载()
operator()(){}
重载()运算符 ----- 函数对象
如果一个类重载了()运算符,那么该类的对象可以称为函数对象
重载的()运算符,返回值类型可以视情况而定 是否引用也可以视情况而定
重载的()运算符函数参数可以任意
在C++中,重载()运算符非常有用,取代了C语言中的函数指针
重载()运算符类的对象 仿函数 函数对象
void operator()(void){
cout << no << ":" << name << ":" << score << endl;
}
void operator()(int age){
cout << no << ":" << name << ":" << age << ":" << score << endl;
}
Stu s1(190,"俞岱岩",89);
s1(); // 函数对象,这个调用无参的重载(),调用即cout << no << ":" << name << ":" << score << endl;
s1(29);//传入参数,另外显示age
利用重载实现的sort()
降序或者升序,决定于class类是
return n2<n1;//升序
return n2>n1;//降序
#include <iostream>
#include <algorithm>
using namespace std;
class IntDesc{
public:
bool operator()(const int& n1,const int& n2){
return n2<n1;
}
};
int main(){
int arr[5] = {9,2,11,8,6};
sort(arr,arr+5);
for(int i=0;i<5;i++)
cout << arr[i] << " ";
cout << endl;
//IntDesc comp; comp(arr[i],arr[i+1])
sort(arr,arr+5,IntDesc());//匿名对象 函数对象
for(int i=0;i<5;i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
重载函数
其实有点类似C中的写一个函数
只是C++中是定义一个函数类,可以随时取名
#include <iostream>
using namespace std;
class Square{
public:
int operator()(int x){
return x * x;
}
int operator()(int x,int y){
return x*x + y*y;
}
};
class Add{
public:
int& operator()(int& x){
return ++x;
}
Add& operator()(){
cout << "---------" << endl;
return *this;
}
};
int main(){
Square f;
cout << f(10) << endl;
cout << f(11,12) << endl;
cout << f((11+12)) << endl;
Add add;
int a = 10;
add(add(add(a)));//13
cout << a << endl;
add()()()()()()(a);//add()add()add()add()...会执行很多次
cout << a << endl;
return 0;
}
重载& 取地址运算符(系统会自动生成const和非const)
#include <iostream>
using namespace std;
class Test{
public:
//Test(const Test& t){}
Test* operator&(void){
cout << "& " << endl;
return this;
}
const Test* operator&(void)const{
cout << "const &" << endl;
return this;
}
};
int main(){
Test t;
cout << &t << endl;
const Test t1;
cout << &t1 << endl;
return 0;
}
因为类中的this本身就是一个指针,所以return this就是该地址
重载SigSet(进制)
准备工作:
void clear(){//16位全部置0
bzero(sigs,16);//memset(sigs,0,16);
}
void full(){//16位全部置1
memset(sigs,0XFF,16);
}
void set(int sig){//[0,127] 80 把这个位置置为1
sigs[sig/8] |= 1<<(sig%8);//
}
void zero(int sig){//把这个位置置为0
sigs[sig/8] &= ~(1<<(sig%8));
}
bool issets(int sig){//判断这个位置是不是1
return (sigs[sig/8] >> (sig%8)) & 1;
}
#include <iostream>
#include <strings.h>
#include <cstring>
using namespace std;
class SigSet{
private:
char sigs[16]; //128个二进制位 128个信号 sigs[0] 最右一位
public:
SigSet(){
clear();
}
SigSet operator~(void)const{
SigSet s(*this);
for(int i=0;i<16;i++){
s.sigs[i] = ~s.sigs[i]; //递归调用了
}
return s;
}
SigSet operator&(const SigSet& s)const{
SigSet sets;
for(int i=0;i<16;i++){
sets.sigs[i] = sigs[i]&s.sigs[i];
}
return sets;
}
SigSet operator|(const SigSet& s)const{
SigSet sets;
for(int i=0;i<16;i++){
sets.sigs[i] = sigs[i]|s.sigs[i];
}
return sets;
}
SigSet operator^(const SigSet& s)const{
SigSet sets;
for(int i=0;i<16;i++){
sets.sigs[i] = sigs[i]^s.sigs[i];
}
return sets;
}
SigSet operator>>(int num){
cout << "right move" << endl;
return *this;
}
SigSet operator<<(int num){
cout << "left move" << endl;
return *this;
}
void clear(){
bzero(sigs,16);//memset(sigs,0,16);
}
void full(){
memset(sigs,0XFF,16);
}
void set(int sig){//[0,127] 80
sigs[sig/8] |= 1<<(sig%8);//
}
void zero(int sig){
sigs[sig/8] &= ~(1<<(sig%8));
}
bool issets(int sig){
return (sigs[sig/8] >> (sig%8)) & 1;
}
friend ostream& operator<<(ostream& os,const SigSet& s);
};
ostream& operator<<(ostream& os,const SigSet& s){
for(int i=0;i<16;i++){
for(int j=0;j<8;j++){
os << (((s.sigs[i])>>j) & 1);
}
}
return os;
}
int main(){
SigSet s;
s.full();
cout << s << endl;
s.clear();
cout << s << endl;
s.set(0);
s.set(8);
s.set(12);
s.set(13);
cout << s << endl;
for(int i=48;i<96;i++)
s.set(i);
cout << s << endl;
SigSet s1;
for(int i=0;i<100;i++){
if(i%2 == 0){
s1.set(i);
}
}
cout << s1 << endl;
cout << ~s1 << endl;
cout << (s1&s) << endl;
cout << (s1|s) << endl;
cout << (s1^s) << endl;
cout << (s1<<3) << endl;
cout << (s1>>10) << endl;
return 0;
}
重载->* (解引用)
#include <iostream>
using namespace std;
class A{
public:
int x;
int y;
public:
A():x(1024),y(9527){}
void func(){
cout << "This is A's object function." << endl;
}
};
class PA{
private:
A *pa;
public:
PA(const A& a){
pa = new A(a);
}
~PA(){
delete pa;
}
A& operator*(void){
return *pa;
}
A* operator->(void){
return pa;
}
//.*不能重载 ->*能够重载
//A& operator.*(void){}
int operator->*(int x){
if(x==1)
return pa->x;
else
return pa->y;
}
};
int main(){
A a;
a.func();
A* ps = &a;
ps->func();
PA pa(a);
(*pa).func();
pa->func();//(pa->)->func();
cout << (pa->*1) << endl;
cout << (pa->*2) << endl;
string s("Hello world");
cout << s[0] << endl;
return 0;
}
成员指针
//.*不可以重载 //->*能够重载
直接成员解引用 间接成员解引用
单参构造函数 和 explicit
如果一个类提供了"单参"构造函数,
那么通过参数类型的对象可以通过调用该单参构造函数转化为该类类型的对象
class A{
public:
A(const B& b){} //B类型的对象可以转换为A类型对象
};
如果在单参构造函数前加上explicit关键字,就可以防止该种"隐式转换",
必须通过显式方式进行构造对象
#include <iostream>
using namespace std;
class Integer{
private:
int num;
public:
//explicit
//explicit
Integer(int num=0):num(num){
}
friend ostream& operator<<(ostream& os,const Integer& i){
return os << i.num;
}
};
class Stu{
private:
int no;
string name;
int score;
public:
Stu(int no):no(no){
cout << "Stu(int)" << endl;
}
explicit Stu(string name):name(name){
cout << "Stu(string)" << endl;
}
Stu(const Integer& i){
cout << "Stu(Integer)" << endl;
}
Stu& operator=(const Stu& s){
cout << "=" << endl;
}
};
int main(){
Integer i1 = 100;
cout << i1 << endl;
i1 = 1024;
cout << i1 << endl;
Stu s = 111;//Stu s(111);
cout << "--------" << endl;
s = 1024;// s = Stu(1024);
cout << "--------" << endl;
//显式调用单参构造
s = Stu(string("Hello")); //s = Stu(string("Hello"))
cout << "--------" << endl;
s = i1; // s = Stu(i1);
cout << "--------" << endl;
//int x = static_cast<int>(s);
return 0;
}
重载类型运算符
源类型 和 目标类型
如果源类型和目标类型都是基础数据类型,
那么源类型和目标类型可以进行想到转换(隐式转换)
如果源类型和目标类型都是自定义类型,
那么从源类型转换到目标类型,可以在目标类型中添加 源类型的单参构造函数
也可以在源类型中 重载 目标类型运算符 函数 添加operator 目标类型(){}
只能二选其一,不能两个都实现
如果源类型是自定义类型, 目标类型是基础数据类型
只能在源类型中 重载 这个基础数据类型运算符函数
如果源类型是基础数据类型,目标类型是自定义类型
则需要在目标类型中定义 源类型的单参构造函数
class A{
public:
A(const B& b){}//B类型对象--->A类型对象
operator B(void)const{//在A类中重载B类型运算符 A类型对象-->B类型对象
}
};
#include <iostream>
using namespace std;
class Integer{
private:
int num;
public:
Integer(int num=0){}
//Integer(Stu s){}//Stu --> Intger
operator int (void)const{//Inetger ---> int
return num;
}
};
class Stu{
private:
int no;
string name;
float high;
public:
Stu(int no=0,string name="",float high=0):no(no),name(name),high(high){}
//重载类型运算符
operator int(void){
return no;
}
operator string(void){
return name;
}
operator float(void){
return high;
}
operator Integer(void ){//Stu --> Integer
return no;//Integer(x,y,z);
}
};
int main(){
Integer i = 1024;
//int x = static_cast<int>(i);
int x = i;
Stu s(110,"宋远桥",170);
x = s;
string name = s;
float y = s;
cout << x << endl;
cout << name << endl;
cout << y << endl;
i = s;
//s = i;
return 0;
}
new和delete重载
class A{
public:
A(const B& b){}//B类型对象--->A类型对象
operator B(void)const{//在A类中重载B类型运算符 A类型对象-->B类型对象
}
};
重载new/delete运算符
在类里用静态方法
#include <iostream>
#include <cstdlib>
using namespace std;
class Test{
private:
int x;
public:
Test(int x=0):x(x){
cout << "构造函数" << endl;
}
~Test(void){
cout << "析构函数" << endl;
}
static void* operator new(size_t size){
cout << "aaa operator new: " << size << endl;
void *pt = malloc(size);
return pt;
}
static void *operator new[](size_t size){
cout << "operator new [] :" << size << endl;
void *ptr = malloc(size);
return ptr;
}
static void operator delete(void *ptr){
cout << "operator delete" << endl;
free(ptr);
}
static void operator delete[](void *ptr){
cout << "operator delete[]" << endl;
}
};
void* operator new(size_t size){
cout << "operator new: " << size << endl;
void *pt = malloc(size);
return pt;
}
void *operator new[](size_t size){
cout << "operator new [] :" << size << endl;
void *ptr = malloc(size);
return ptr;
}
void operator delete(void *ptr){
cout << "operator delete" << endl;
free(ptr);
}
void operator delete[](void *ptr){
cout << "operator delete[]" << endl;
}
int main(){
Test *pt = new Test(1024);
delete pt;//对象
pt = new Test[10];
delete [] pt;
return 0;
}
C++实现分数表示(利用重载)
& 取地址运算符
编译器自动生成两个&运算符函数 返回对象的地址
形式:
class CLA_NAME{
CLA_NAME *operator&(void){
return this;
}
const CLA_NAME* operator&(void)const{
return this;
}
};
#include <iostream>
using namespace std;
int maxdiv(int m,int n){
if(m==0||n==0)
return 0;
while(m%n!=0){
int res = m%n;
m = n;
n = res;
}
return n;
}
class Fraction{
private:
int mole;//分子
int deno;//分母
public:
Fraction(int mode=0,int deno=1):mole(mole),deno(deno){}
Fraction operator+(const Fraction& f)const{
return Fraction(mole*f.deno+deno*f.mole,deno*f.deno);
}
Fraction operator-(const Fraction& f)const{
return Fraction(mole*f.deno-deno*f.mole,deno*f.deno);
}
Fraction operator*(const Fraction& f)const{
return Fraction(mole*f.mole,deno*f.deno);
}
Fraction operator/(const Fraction& f)const{
return Fraction(mole*f.deno,deno*f.mole);
}
void simplify(){
int m = maxdiv(mole,deno);
mole /= m;
deno /= m;
}
//+= -= *= /=
friend Fraction& operator+=(Fraction& f1,const Fraction& f2);
friend Fraction& operator-=(Fraction& f1,const Fraction& f2);
friend Fraction& operator*=(Fraction& f1,const Fraction& f2);
friend Fraction& operator/=(Fraction& f1,const Fraction& f2);
//>> << 只能以友元方式重载
friend ostream& operator<<(ostream& os,const Fraction& f);
friend istream& operator>>(istream& is,Fraction& f);
};
ostream& operator<<(ostream& os,const Fraction& f){
const_cast<Fraction&>(f).simplify();
return os << f.mole << "/" << f.deno;
}
istream& operator>>(istream& is,Fraction& f){
return is >> f.mole >> f.deno;
}
//::oeprator+=(f1,f2); f1 += f2;
Fraction& operator+=(Fraction& f1,const Fraction& f2){
f1.mole = f1.mole*f2.deno + f1.deno*f2.mole;
f1.deno = f1.deno*f2.deno;
return f1;
}
Fraction& operator-=(Fraction& f1,const Fraction& f2){
f1.mole = f1.mole*f2.deno - f1.deno*f2.mole;
f1.deno = f1.deno*f2.deno;
return f1;
}
Fraction& operator*=(Fraction& f1,const Fraction& f2){
f1.mole *= f2.mole;
f1.deno *= f2.deno;
return f1;
}
Fraction& operator/=(Fraction& f1,const Fraction& f2){
f1.mole *= f2.deno;
f1.deno *= f2.mole;
return f1;
}
//约分的问题
int main(){
Fraction f;
cin >> f;
cout << f << endl;
return 0;
}
实现日期++ – (利用重载)
#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std;
class Date{
private:
int year;
unsigned int mon;
unsigned int day;
public:
Date(){//当前系统时间
time_t t = time(NULL);
struct tm *pt = localtime(&t);
year = pt->tm_year+1900;
mon = pt->tm_mon+1;
day = pt->tm_mday;
}
Date(int year,unsigned int mon,unsigned int day):year(year),mon(mon),day(day){
//写个函数 把该日期检验成一个有效的日期
}
bool leap()const{
return year%4==0&&year%100!=0||year%400==0;
}
bool small()const{
return mon==4||mon==6||mon==9||mon==11;
}
unsigned int getDaysOfMon()const{
if(mon == 2){
return 28+leap();
}else{
return 31-small();
}
}
bool valid()const{
if(mon<=0 || mon>=13 || day<=0 || day>getDaysOfMon())
return false;
return true;
}
Date& operator++(void){
if(valid()){
if(day == 31){
day=1;
if(mon==12){
++year;
mon = 1;
}else{
++mon;
}
}else if(day==30){
if(small()){
++mon;
day = 1;
}else{
++day;
}
}else if(day==29){
if(mon == 2){
mon = 3;
day = 1;
}else{
++day;
}
}else if(day==28){
if(!leap() && mon == 2){
mon = 3;
day = 1;
}else{
++day;
}
}else{
++day;
}
}
return *this;
}
Date operator++(int){
Date d(*this);
++(*this);//调用前++
return d;
}
//sort 比较 C万能排序
bool operator<(const Date& d)const{
if(year!=d.year)
return year < d.year;
if(mon!=d.mon)
return mon < d.mon;
return day < d.day;
}
bool operator<=(const Date& d)const{
if(year!=d.year)
return year < d.year;
if(mon!=d.mon)
return mon < d.mon;
return day <= d.day;
}
//a > b b < a
bool operator>(const Date& d)const{//*this > d
return d < *this;// d.operator<(*this);
}
bool operator>=(const Date& d)const{
return d <= *this; //d.operator<=(*this);
}
bool operator==(const Date& d)const{
return year==d.year && mon==d.mon && day==d.day;
}
bool operator!=(const Date& d)const{
return !(*this==d);
}
friend Date& operator--(Date& d);
friend Date operator--(Date& d,int);
friend ostream& operator<<(ostream& os,const Date& d);
friend istream& operator>>(istream& is,Date& d);
};
ostream& operator<<(ostream& os,const Date& d){
if(d.valid())
return os << d.year << "-" << d.mon << "-" << d.day;
return os << "not a date";
}
istream& operator>>(istream& is,Date& d){
return is >> d.year >> d.mon >> d.day;
}
Date& operator--(Date& d){
if(d.valid()){
if(d.day == 1){
if(d.mon == 1){
--d.year;
d.mon = 12;
d.day = 31;
}else if(d.mon == 3){
d.mon = 2;
d.day = 28+d.leap();
}else if(d.mon == 5||d.mon == 7||d.mon==10||d.mon==12){
--d.mon;
d.day = 30;
}else{
--d.mon;
d.day = 31;
cout << d.year << "-" << d.mon << "-" << d.day << endl;
}
}else{
--d.day;
}
}
return d;
}
Date operator--(Date& d,int){
Date old(d);
--d;
return old;
}
//在C++ STL 大量使用了 函数对象
class DateDesc{
public:
bool operator()(const Date& d1,const Date& d2){
return d2<d1;
}
};
int main(){
Date d; //2021 9 2
cout << d << endl;
cin >> d;
cout << d << endl;
Date d1 = --d;
cout << d << endl;
Date d2 = d--;
cout << d1 << endl;
cout << d2 << endl;
cout << d << endl;
int arr[5] = {3,9,2,7,6};
sort(arr,arr+5);
for(int i=0;i<5;i++)
cout << arr[i] << " ";
cout << endl;
Date ds[5] = {Date(),Date(2020,12,31),Date(2020,11,11),Date(2021,7,3),Date(2021,3,2)};
sort(ds,ds+5,DateDesc());//C++不用函数指针 函数对象
for(int i=0;i<5;i++)
cout << ds[i] << endl;
d1 == d2;
return 0;
}
总结
C++11之前的版本中,如果有一个空类(啥也没写),至少有6个函数
无参构造 拷贝构造 拷贝赋值 析构函数 取址函数(2个 const版本和非const版本)
C++11之前一个类中最少会有几个函数? 5个
手动实现一个拷贝构造函数 无参构造将不会自动生成
C++11版本会自动再添加两个函数:
移动拷贝构造函数
移动拷贝赋值函数
C++11中的移动拷贝构造函数和移动拷贝赋值函数
T t1(move(t));//移动构造,C++的函数move
T t2;
t2 = t2+t2;//移动赋值
#include <iostream>
using namespace std;
class T{
public:
T(){
cout << "无参构造" << endl;
}
//拷贝构造
T(const T& t){
cout << "拷贝构造" << endl;
}
//移动拷贝构造
T(T&& t){
cout << "移动拷贝构造" << endl;
}
//移动赋值函数
T& operator=(T&& t){
cout << "移动赋值函数" << endl;
}
T& operator=(const T& t){
cout << "拷贝赋值" << endl;
return *this;
}
~T(void){
cout << "析构函数" << endl;
}
T* operator&(void){
cout << "operator&(void)" << endl;
return this;
}
const T* operator&(void)const{
cout << "operator&(void)const" << endl;
return this;
}
T operator+(const T& t)const{
return T();
}
};
int main(){
T t;
T t1(move(t));
T t2;
t2 = t2+t2;//移动赋值
return 0;
}
运算符重载总结
单目 双目 三目 …
1.操作数至少有一个是类类型对象
2.不是所有的运算符都能够重载
不能重载的运算符有:
::作用域限定符
. 直接成员访问运算符
.* 直接成员指针解引用运算符
?: 三目运算符
sizeof: 求字节数运算符
typeid: 获取类型信息运算符
3.不是所有的运算符都可以用全局函数的方式重载
只能以成员方式重载的运算符:
= 拷贝赋值
[] 下标运算符
() 函数运算符
-> 间接成员访问运算符
4.不是所有运算符都可以用成员方式重载
只能以友元方式重载:
<< 输出运算符
>> 输入运算符
5.不能发明新的运算符
x ** y
6.一般来说保持运算符本身的特性
->*
7.经常重载的运算符
() 函数运算符
< 小于运算符
== != 比较运算符
>> << 输入输出运算符
[] 下标运算符