5.5-day05-C++单目操作符/继承
二、
2.+=/-=/*=...
左变右不变。
表达式的值是左值,左操作数的引用。
(a += b) = c;
3.<</>>
int i = 10;
float f = 1.23;
Complex c (...);
cout << c << i << f << endl;
cin >> c;
左操作数ostream/istream类型,不能是常量,不能拷贝。
右操作数自定义类型,对于<<可以是常量,对于>>不能是常量。
表达式的值是左操作数的引用。
::operator<< (cout, c).operator<< (i).operator<< (f).operator<< (endl);
三、单目操作符
1.-(取负)/!/~
操作数不变。
表达式的值是右值。
2.前++/前--
操作数变。
表达式的值是运算以后的值。
表达式的值是左值,操作数的引用。
(++i) = 100;
++++++i;
3.后++/后--
操作数变。
表达式的值是运算以前的值。
表达式的值是右值。
四、其它操作符
1.下标操作符:[]
int arr[10] = { ... };
arr[1] = 10;
cout << arr[1] << endl;
-----------------------
class Array { ... };
Array arr (...);
arr[1] = 10;
cout << arr[1] << endl;
双目操作符,左操作数是一个具有容器特性的对象,右操作数是容器中特定数据元素的索引(基零的下标)。
下标表达式的值可以是左值,也可以是右值,由容器对象的常属性决定。常容器下标表达式的值是右值,非常容器下标表达式的值是左值。
2.函数操作符:()
如果为一个类定义了形如:
返回类型 operator() (形参表) {...}
的操作符函数,那么这个类所实例化的对象就可以被当做函数使用。
3.解引用(*)和间接访问(->)操作符
以指针的方式使用类类型的对象。
4.自定义类型转换和类型转换操作符
1)通过单参构造实现自定义类型转换
如果A类中有一个可以接受B类对象做为唯一参数的构造函数,那么B类型的对象就可以根据该构造函数被转换为A类型。
通过explicit关键字,可以强制使用该构造函数所完成的类型转换必须显示进行。
2)通过类型转换操作符函数实现自定义类型转换
如果A类中有一个形如
operator B (void) const { ... }
的操作符函数,那么A类型的对象就可以根据该函数被转换为B类型。
3)如果目标类型是类类型,源类型是基本类型,那么就只能通过在目标类型中定义以源类型为单参的构造函数实现类型转换。如果目标类型是基本类型,源类型是类类型,那么就只能通过在源类型中定义以目标类型为函数名的类型转换操作符函数实现类型转换。如果目标类型和源类型都是类类型,那么以上两种方法任取其一,但是不能同时使用。如果目标类型和源类型都是基本类型,那么无法实现自定义类型转换。
5.new/delete操作符
1.cpp
#include<iostream>
usingnamespace std;
int main (void){
int i =0;
(i++)=100;
cout << i << endl;
cout << i++++++<< endl;// 103
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225930853-1700729734.png)
array.cpp
#include<iostream>
usingnamespace std;
classArray{
public:
Array(size_t size =1):
m_data (newint[size]){}
~Array(void){
if(m_data){
delete m_data;
m_data = NULL;
}
}
int&operator[](size_t i){
return m_data[i];
}
constint&operator[](size_t i)const{
returnconst_cast<Array&>(*this)[i];
}
private:
int* m_data;
};
int main (void){
Array arr (10);
for(size_t i =0; i <10;++i)
arr[i]= i;// arr.operator[](i) = i;
arr[0]++;
constArray& cr = arr;
for(size_t i =0; i <10;++i)
cout << cr[i]<<' ';
cout << endl;
// cr[0]++;
return0;
}
const常对象的下标操作,返回右值;
右值,即具有只读属性,不能进行赋值;
return const_cast<Array&> (*this)[i];
去常,变为普通引用;
int&operator[](size_t i){
return m_data[i];
}
非常对象的下标操作,返回左值;
c.cpp
#include<iostream>
usingnamespace std;
classComplex{
public:
Complex(int r =0,int i =0):
m_r (r), m_i (i){}
void print (void)const{
cout << m_r <<'+'<< m_i <<'i'<< endl;
}
private:
int m_r;
int m_i;
};
int main (void){
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225932078-473727999.png)
complex1.cpp
#include<iostream>
usingnamespace std;
classComplex{
public:
Complex(int r =0,int i =0):
m_r (r), m_i (i){}
void print (void)const{
cout << m_r <<'+'<< m_i <<'i'<< endl;
}
Complex&operator+=(constComplex& r){
m_r += r.m_r;
m_i += r.m_i;
return*this;
}
friendComplex&operator-=(Complex& l,
constComplex& r){
l.m_r -= r.m_r;
l.m_i -= r.m_i;
return l;
}
private:
int m_r;
int m_i;
};
int main (void){
Complex c1 (1,2), c2 (3,4);
c1 += c2;// c1.operator+= (c2)i
c1.print ();// 4+6i
Complex c3 (5,6);
(c1 += c2)= c3;
c1.print ();// 5+6i
c1 -= c2;// ::operator-= (c1, c2)
c1.print ();// 2+2i
(c1 -= c2)= c3;
c1.print ();// 5+6i;
return0;
}
operator操作符重载:
complex2.cpp
#include<iostream>
usingnamespace std;
classComplex{
public:
Complex(int r =0,int i =0):
m_r (r), m_i (i){}
void print (void)const{
cout << m_r <<'+'<< m_i <<'i'<< endl;
}
friend ostream&operator<<(ostream& os,
constComplex& r){
return os << r.m_r <<'+'<< r.m_i <<'i';
}
friend istream&operator>>(istream& is,
Complex& r){
return is >> r.m_r >> r.m_i;
}
private:
int m_r;
int m_i;
};
int main (void){
Complex c1 (1,2), c2 (3,4);
cout << c1 << endl << c2 << endl;
// ::operator<<(::operator<<(cout,c1).operator<<(
// endl),c2).operator<<(endl);
cin >> c1 >> c2;
cout << c1 << endl << c2 << endl;
return0;
}
complex3.cpp
#include<iostream>
usingnamespace std;
classComplex{
public:
Complex(int r =0,int i =0):
m_r (r), m_i (i){}
void print (void)const{
cout << m_r <<'+'<< m_i <<'i'<< endl;
}
constComplexoperator-(void)const{
returnComplex(-m_r,-m_i);
}
friendconstComplexoperator~(
constComplex& o){
returnComplex(o.m_i, o.m_r);
}
private:
int m_r;
int m_i;
};
int main (void){
constComplex c1 (1,2);
Complex c2 =-c1;// c2=c1.operator-()
c2.print ();// -1+-2i
Complex c3 =~c1;// c3=::operator~(c1)
c3.print ();// 2+1i;
return0;
}
complex4.cpp
#include<iostream>
usingnamespace std;
classComplex{
public:
Complex(int r =0,int i =0):
m_r (r), m_i (i){}
void print (void)const{
cout << m_r <<'+'<< m_i <<'i'<< endl;
}
Complex&operator++(void){
++m_r;
++m_i;
return*this;
}
friendComplex&operator--(Complex& o){
--o.m_r;
--o.m_i;
return o;
}
private:
int m_r;
int m_i;
};
int main (void){
Complex c1 (1,2);
Complex c2 =++c1;// c2=c1.operator++()
c1.print ();// 2+3i
c2.print ();// 2+3i
(++c1)=Complex(10,20);
c1.print ();// 10+20i;
(++++++c1).print ();// 13+23i
c2 =--c1;// c2=::operator--(c1)
c1.print ();// 12+22i
c2.print ();// 12+22i
return0;
}
深刻理解operator操作符重载:用于复数的表示:
complex5.cpp
#include<iostream>
usingnamespace std;
classComplex{
public:
Complex(int r =0,int i =0):
m_r (r), m_i (i){}
void print (void)const{
cout << m_r <<'+'<< m_i <<'i'<< endl;
}
constComplexoperator++(int){
Complex old (*this);
++m_r;
++m_i;
return old;
}
friendconstComplexoperator--(Complex& o,
int){
Complex old (o);
--o.m_r;
--o.m_i;
return old;
}
private:
int m_r;
int m_i;
};
int main (void){
Complex c1 (1,2);
Complex c2 = c1++;// c2=c1.operator++(0)
c1.print ();// 2+3i;
c2.print ();// 1+2i;
// (c1++) = c2;
// c1++++++;
c2 = c1--;// c2=::operator--(c1,0)
c1.print ();// 1+2i
c2.print ();// 2+3i
return0;
}vi
date.cpp
// 日期运算。
// 实现日期类,支持如下运算:
// +/+=:增加指定的天数;
// -/-=:减去指定的天数;
// - :两日期相差天数。
// >> :接受形如2012 1 14格式输入;
// << :以形如2012-1-14的格式输出;
#include<iostream>
usingnamespace std;
classDate{
public:
Date(int nYear =0,int nMonth =0,
int nDay =0):
m_nYear (nYear), m_nMonth (nMonth),
m_nDay (nDay){}
Dateoperator+(int nDays)const{
returnDays2Date(Date2Days()+ nDays);
}
Date&operator+=(int nDays){
return*this=*this+ nDays;
}
Dateoperator-(int nDays)const{
returnDays2Date(Date2Days()- nDays);
}
Date&operator-=(int nDays){
return*this=*this- nDays;
}
intoperator-(constDate& date)const{
returnDate2Days()- date.Date2Days();
}
friend istream&operator>>(istream& is,
Date& date){
return is >> date.m_nYear >> date.m_nMonth
>> date.m_nDay;
}
friend ostream&operator<<(ostream& os,
constDate& date){
return os << date.m_nYear <<"-"
<< date.m_nMonth <<"-"<< date.m_nDay;
}
private:
intDate2Days(void)const{
int nDays =(m_nYear -1)*365;
for(int nYear =1; nYear < m_nYear;
nYear++)
if(IsLeap(nYear))
nDays++;
for(int nMonth =0; nMonth < m_nMonth -1;
nMonth++)
if(IsLeap(m_nYear))
nDays += s_nDaysOfMonth[1][nMonth];
else
nDays += s_nDaysOfMonth[0][nMonth];
nDays += m_nDay;
return nDays;
}
DateDays2Date(int nDays)const{
int nYear =1;
for(;;){
if(IsLeap(nYear)){
if(nDays <=366)
break;
nDays -=366;
}
else{
if(nDays <=365)
break;
nDays -=365;
}
nYear++;
}
int nMonth =1;
bool bLeap =IsLeap(nYear);
for(;;){
if(bLeap){
if(nDays <=
s_nDaysOfMonth[1][nMonth-1])
break;
nDays-=s_nDaysOfMonth[1][nMonth-1];
}
else{
if(nDays <=
s_nDaysOfMonth[0][nMonth-1])
break;
nDays-=s_nDaysOfMonth[0][nMonth-1];
}
nMonth++;
}
returnDate(nYear, nMonth, nDays);
}
boolIsLeap(int nYear)const{
return(nYear %4==0&& nYear %100!=0)
|| nYear %400==0;
}
int m_nYear;
int m_nMonth;
int m_nDay;
staticint s_nDaysOfMonth[][12];
};
intDate::s_nDaysOfMonth[][12]={
{31,28,31,30,31,30,31,31,30,31,30,31},
{31,29,31,30,31,30,31,31,30,31,30,31}
};
int main (void){
cout <<"Enter a date: ";
Date d1;
cin >> d1;
cout <<"Enter the number of days: ";
int nDays;
cin >> nDays;
Date d2 = d1 + nDays;
cout << d1 <<" + "<< nDays <<" = "<< d2
<< endl;
Date d3 (d1);
d3 += nDays;
cout << d1 <<" += "<< nDays <<" -> "<< d3
<< endl;
cout <<"Enter a date: ";
cin >> d1;
cout <<"Enter the number of days: ";
cin >> nDays;
d2 = d1 - nDays;
cout << d1 <<" - "<< nDays <<" = "<< d2
<< endl;
d3 = d1;
d3 -= nDays;
cout << d1 <<" -= "<< nDays <<" -> "<< d3
<< endl;
cout <<"Enter a date: ";
cin >> d1;
cout <<"Enter another date: ";
cin >> d2;
cout <<"The days between those dates is "
<< d2 - d1 << endl;
return0;
}
integer.cpp
#include<iostream>
usingnamespace std;
classSquare{
public:
doubleoperator()(double x){
return x * x;
}
};
classInteger{
public:
explicitInteger(int i =0): m_i (i){}
void print (void)const{
cout << m_i << endl;
}
Integer&operator()(int i){
m_i += i;
return*this;
}
Integer&operator,(int i){
m_i += i;
return*this;
}
operatorint(void)const{
return m_i;
}
private:
int m_i;
};
void foo (constInteger& i){
i.print ();
}
Integer bar (void){
returnInteger(300);
}
int main (void){
Square square;
cout << square (3)<< endl;
// cout << square.operator() (3) << endl;
Integer i (10);
i (1)(2)(3)(17);
i.print ();// 33
i,1,2,3,17;
i.print ();// 56
i =(Integer)100;
i.print ();
foo (static_cast<Integer>(200));
bar ().print ();
int n = i;
cout << n << endl;
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225937139-1410679095.png)
通过explicit关键字,可以强制使用该构造函数所完成的类型转换必须显示进行。
m33.cpp
#include<iomanip>
#include<iostream>
usingnamespace std;
class M33 {
public:
M33 (void){
for(int i =0; i <3; i++)
for(int j =0; j <3; j++)
m_a[i][j]=0;
}
M33 (int a[][3]){
for(int i =0; i <3; i++)
for(int j =0; j <3; j++)
m_a[i][j]= a[i][j];
}
const M33 operator+(const M33& m)const{
int a[3][3];
for(int i =0; i <3; i++)
for(int j =0; j <3; j++)
a[i][j]= m_a[i][j]+ m.m_a[i][j];
return a;
}
const M33 operator-(const M33& m)const{
int a[3][3];
for(int i =0; i <3; i++)
for(int j =0; j <3; j++)
a[i][j]= m_a[i][j]- m.m_a[i][j];
return a;
}
const M33 operator*(const M33& m)const{
int a[3][3]={0};
for(int i =0; i <3; i++)
for(int j =0; j <3; j++)
for(int k =0; k <3; k++)
a[i][j]+=m_a[i][k]*m.m_a[k][j];
return a;
}
M33&operator+=(const M33& m){
return*this=*this+ m;
}
M33&operator-=(const M33& m){
return*this=*this- m;
}
M33&operator*=(const M33& m){
return*this=*this* m;
}
const M33 operator-(void)const{
return M33 ()-*this;
}
M33&operator++(void){
for(int i =0; i <3; i++)
for(int j =0; j <3; j++)
m_a[i][j]++;
return*this;
}
M33&operator--(void){
for(int i =0; i <3; i++)
for(int j =0; j <3; j++)
m_a[i][j]--;
return*this;
}
const M33 operator++(int){
M33 m =*this;
++(*this);
return m;
}
const M33 operator--(int){
M33 m =*this;
--(*this);
return m;
}
friend ostream&operator<<(ostream& os,
const M33& m){
for(int i =0; i <3; i++){
for(int j =0; j <3; j++)
os << setw (4)<< m.m_a[i][j];
os << endl;
}
return os;
}
private:
int m_a[3][3];
};
int main (void){
int a1[3][3]={1,2,3,4,5,6,7,8,9};
M33 m1 (a1);
int a2[3][3]={9,8,7,6,5,4,3,2,1};
M33 m2 (a2);
cout << m1 + m2 << endl;
cout << m1 - m2 << endl;
cout << m1 * m2 << endl;
m1 += m2;
cout << m1 << endl;
m1 -= m2;
cout << m1 << endl;
m1 *= m2;
cout << m1 << endl;
cout <<-m1 << endl;
cout <<++m2 << endl;
cout << m2 << endl;
cout <<--m2 << endl;
cout << m2 << endl;
cout << m2++<< endl;
cout << m2 << endl;
cout << m2--<< endl;
cout << m2 << endl;
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225938114-566601061.png)
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225938425-538506948.png)
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225938746-485112959.png)
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225938998-374568841.png)
cout << m1 + m2 << endl;
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225939221-841201752.png)
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225939423-1386727396.png)
(1) 常对象
用const修饰的对象叫对象常量,其格式如下:〈类名〉const 〈对象名〉 或者 const 〈类名〉〈对象名〉
声明为常对象的同时必须被初始化,并从此不能改写对象的数据成员。
const M33 operator+(const M33& m)const
常对象常被用在对象的引用上。所谓常引用是指说明引用时用const修饰。
常引用所引用的对象不能被更新,一般用做形参。其格式:
const 〈类型说明〉&〈引用名〉
const M33 operator+(const M33& m)const
(2)常成员函数
用const关键词说明的函数叫常成员函数。其格式如下:
〈类型〉〈函数名〉(〈参数表〉)const;
〈类型〉〈函数名〉(〈参数表〉)const;
const M33 operator+(const M33& m)const
new.cpp
#include<iostream>
#include<cstdlib>
usingnamespace std;
class A {
public:
~A (void){}
staticvoid*operatornew(size_t size){
void* p = malloc (size);
cout <<"我的new :"<< p <<' '
<< size << endl;
return p;
}
staticvoidoperatordelete(void* p){
cout <<"我的delete:"<< p << endl;
free (p);
}
staticvoid*operatornew[](size_t size){
void* p = malloc (size);
cout <<"我的new[] :"<< p <<' '
<< size << endl;
return p;
}
staticvoidoperatordelete[](void* p){
cout <<"我的delete[]:"<< p << endl;
free (p);
}
private:
int m_i;
double m_d;
char m_c;
};// IIIIDDDDDDDDCXXX
int main (void){
cout <<sizeof(A)<< endl;
A* pa =new A;
cout << pa << endl;
delete pa;
pa =new A[2];
cout << pa << endl;
delete[] pa;
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225939890-1672959306.png)
到下列东西时要用
#include <cstdlib>
字符转换函数:atof,atoi,atol,strtod,strtol,strtoul
伪随机数函数:rand,srand
动态分配内存函数:calloc,free,malloc,realloc
环境函数:abort,atexit,exit,getenv,system
查找,分类函数:bsearch,qsort
整数计算函数:abs,div,labs,ldiv,
多字节文字(中日韩文)函数:mblen,mbtowc,wctombmbstowcs,wcstombs, 宏:EXIT_FAILURE,EXIT_SUCCESS,MB_CUR_MAX,NULL,RAND_MAX, 类型:div_t,ldiv_t,size_t
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225940166-1188883415.png)
delete pa; 局部释放
delete[ ] pa; 全部释放
ptr.cpp
#include<iostream>
#include<memory>
usingnamespace std;
class A {
public:
A (void){
cout <<"构造"<< endl;
}
~A (void){
cout <<"析构"<< endl;
}
void hello (void){
cout <<"Hello, World !"<< endl;
}
};
class PA {
public:
PA (A* p = NULL): m_p (p){}
~PA (void){
if(m_p){
delete m_p;
m_p = NULL;
}
}
A&operator*(void)const{
return*m_p;
}
A*operator->(void)const{
// return &**this;
return m_p;
}
PA (PA& that): m_p (that.release ()){}
PA&operator=(PA& that){
if(&that !=this)
reset (that.release ());
return*this;
}
private:
A* release (void){
A* p = m_p;
m_p = NULL;
return p;
}
void reset (A* p){
if(p != m_p){
delete m_p;
m_p = p;
}
}
A* m_p;
};
void bar (auto_ptr<A> pa){
cout <<"bar:";
pa -> hello ();
}
void foo (void){
PA pa (new A);
// A* pa = new A;
// pa -> hello ();
// (*pa).hello ();
// A* pb = pa;
pa -> hello ();// pa.operator->()->hello();
(*pa).hello ();// pa.operator*().hello();
PA pb = pa;
pb -> hello ();
auto_ptr<A> pa1 (new A);
pa1 -> hello ();
auto_ptr<A> pa2 = pa1;
(*pa2).hello ();
bar (pa2);
cout << pa2.get ()<< endl;
}
// smart_ptr
int main (void){
foo ();
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225940934-553847479.png)
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225941225-1267044940.png)
若在栈里创建,找到右括号}会析构;
若new 是在堆里,不会自动析构;
PA pa = new A;
在堆里new,析构交给智能指针PA;
--------------------------------------------------------
智能指针:把类类型的对象当作指针来用; // pa 是对象
我们希望用指针的形式去用一个类型的对象;
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225941604-1895075264.png)
拷贝构造:把PA中对象的指针一个个进行传递;
进行拷贝赋值;
先把原来持有的去掉,持新的指针。
智能指针,任何时候都仅持有一个指针。
foo 是成员变量
foobar 是全局变量
barfoo 是 Foo::bar() 的局部变量
bar 的作用是根据某个全局状态和之前计算出来的值修改自身的某个状态
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225941843-1669536505.png)
(1)不能跨作用域;
(2)谨慎复制;
(3)不能使用数组;
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225942126-2078783586.png)
string.cpp
#include<iostream>
#include<cstring>
usingnamespace std;
classString{
public:
String(constchar* str = NULL){
m_str =newchar[strlen(str?str:"")+1];
strcpy (m_str, str ? str :"");
}
~String(void){
if(m_str){
delete[] m_str;
m_str = NULL;
}
}
String(constString& that):
m_str (strcpy (
newchar[strlen(that.m_str)+1],
that.m_str)){}
/* 菜鸟
void operator= (const String& that) {
m_str = new char[strlen(that.m_str)+1];
strcpy (m_str, that.m_str);
}*/
String&operator=(constString& that){
if(&that !=this){
/* 小鸟
delete[] m_str;
m_str = new char[strlen(that.m_str)+1];
strcpy (m_str, that.m_str);
*/
/* 大鸟
char* str =
new char[strlen(that.m_str)+1];
delete[] m_str;
m_str = strcpy (str, that.m_str);
*/
// 老鸟
String temp (that);
swap (m_str, temp.m_str);
}
return*this;
}
constchar* c_str (void)const{
return m_str;
}
operatorconstchar*(void)const{
return c_str ();
}
private:
char* m_str;
};
int main (void){
String s1 ("Hello, World !");
cout << s1.c_str ()<< endl;
String s2 = s1;
cout << s2.c_str ()<< endl;
String s3 ("Hello, Linux !");
try{
s1 = s3;
}
catch(exception& ex){
cout << ex.what ()<< endl;
}
cout << s1.c_str ()<< endl;
constchar* psz = u1;
cout << s1 << endl;
cout << psz << endl;
return0;
}
![](https://img2018.cnblogs.com/blog/1167156/201811/1167156-20181129225942639-932278188.png)
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">