zoukankan      html  css  js  c++  java
  • C++运算符重载

    转自:http://c.biancheng.net/cpp/biancheng/view/3011.html

    一、C++运算符重载的概念和语法

    所谓重载,就是赋予新的含义。函数重载(Function Overloading)可以让一个函数名有多种功能,在不同情况下进行不同的操作。运算符重载(Operator Overloading)也是一个道理,同一个运算符可以有不同的功能。

    实际上,我们已经在不知不觉中使用了运算符重载。例如,+号可以对不同类型(int、float 等)的数据进行加法操作;<<既是位移运算符,又可以配合 cout 向控制台输出数据。C++ 本身已经对这些运算符进行了重载。

    C++ 也允许程序员自己重载运算符,这给我们带来了很大的便利。

    下面的代码定义了一个复数类,通过运算符重载,可以用+号实现复数的加法运算:

    1. #include <iostream>
    2. using namespace std;
    3. class complex{
    4. public:
    5. complex();
    6. complex(double real, double imag);
    7. public:
    8. //声明运算符重载
    9. complex operator+(const complex &A) const;
    10. void display() const;
    11. private:
    12. double m_real; //实部
    13. double m_imag; //虚部
    14. };
    15. complex::complex(): m_real(0.0), m_imag(0.0){ }
    16. complex::complex(double real, double imag): m_real(real), m_imag(imag){ }
    17. //实现运算符重载
    18. complex complex::operator+(const complex &A) const{
    19. complex B;
    20. B.m_real = this->m_real + A.m_real;
    21. B.m_imag = this->m_imag + A.m_imag;
    22. return B;
    23. }
    24. void complex::display() const{
    25. cout<<m_real<<" + "<<m_imag<<"i"<<endl;
    26. }
    27. int main(){
    28. complex c1(4.3, 5.8);
    29. complex c2(2.4, 3.7);
    30. complex c3;
    31. c3 = c1 + c2;
    32. c3.display();
    33. return 0;
    34. }

    运行结果:
    6.7 + 9.5i

    本例中义了一个复数类 complex,m_real 表示实部,m_imag 表示虚部,第 10 行声明了运算符重载,第 21 行进行了实现(定义)。认真观察这两行代码,可以发现运算符重载的形式与函数非常类似。

    运算符重载其实就是定义一个函数,在函数体内实现想要的功能,当用到该运算符时,编译器会自动调用这个函数。也就是说,运算符重载是通过函数实现的,它本质上是函数重载。

    运算符重载的格式为:

    返回值类型 operator 运算符名称 (形参表列){
        //TODO:
    }

    operator是关键字,专门用于定义重载运算符的函数。我们可以将operator 运算符名称这一部分看做函数名,对于上面的代码,函数名就是operator+

    运算符重载函数除了函数名有特定的格式,其它地方和普通函数并没有区别。

    上面的例子中,我们在 complex 类中重载了运算符+,该重载只对 complex 对象有效。当执行c3 = c1 + c2;语句时,编译器检测到+号左边(+号具有左结合性,所以先检测左边)是一个 complex 对象,就会调用成员函数operator+(),也就是转换为下面的形式:

    c3 = c1.operator+(c2);

    c1 是要调用函数的对象,c2 是函数的实参。

    上面的运算符重载还可以有更加简练的定义形式:

    1. complex complex::operator+(const complex &A)const{
    2. return complex(this->m_real + A.m_real, this->m_imag + A.m_imag);
    3. }

    return 语句中的complex(this->m_real + A.m_real, this->m_imag + A.m_imag)会创建一个临时对象,这个对象没有名称,是一个匿名对象。在创建临时对象过程中调用构造函数,return 语句将该临时对象作为函数返回值。

    在全局范围内重载运算符

    运算符重载函数不仅可以作为类的成员函数,还可以作为全局函数。更改上面的代码,在全局范围内重载+,实现复数的加法运算:

    1. #include <iostream>
    2. using namespace std;
    3. class complex{
    4. public:
    5. complex();
    6. complex(double real, double imag);
    7. public:
    8. void display() const;
    9. //声明为友元函数
    10. friend complex operator+(const complex &A, const complex &B);
    11. private:
    12. double m_real;
    13. double m_imag;
    14. };
    15. complex operator+(const complex &A, const complex &B);
    16. complex::complex(): m_real(0.0), m_imag(0.0){ }
    17. complex::complex(double real, double imag): m_real(real), m_imag(imag){ }
    18. void complex::display() const{
    19. cout<<m_real<<" + "<<m_imag<<"i"<<endl;
    20. }
    21. //在全局范围内重载+
    22. complex operator+(const complex &A, const complex &B){
    23. complex C;
    24. C.m_real = A.m_real + B.m_real;
    25. C.m_imag = A.m_imag + B.m_imag;
    26. return C;
    27. }
    28. int main(){
    29. complex c1(4.3, 5.8);
    30. complex c2(2.4, 3.7);
    31. complex c3;
    32. c3 = c1 + c2;
    33. c3.display();
    34. return 0;
    35. }

    运算符重载函数不是 complex 类的成员函数,但是却用到了 complex 类的 private 成员变量,所以必须在 complex 类中将该函数声明为友元函数。

    当执行c3 = c1 + c2;语句时,编译器检测到+号两边都是 complex 对象,就会转换为类似下面的函数调用:

    c3 = operator+(c1, c2);

    小结

    虽然运算符重载所实现的功能完全可以用函数替代,但运算符重载使得程序的书写更加人性化,易于阅读。运算符被重载后,原有的功能仍然保留,没有丧失或改变。通过运算符重载,扩大了C++已有运算符的功能,使之能用于对象。

    二、C++运算符重载的规则

    运算符重载是通过函数重载实现的,概念上大家都很容易理解,这节我们来说一下运算符重载的注意事项。

    1) 并不是所有的运算符都可以重载。能够重载的运算符包括:
    +  -  *  /  %  ^  &  |  ~  !  =  <  >  +=  -=  *=  /=  %=  ^=  &=  |=  <<  >>  <<=  >>=  ==  !=  <=  >=  &&  ||  ++  --  ,  ->*  ->  ()  []  new  new[]  delete  delete[]

    上述运算符中,[]是下标运算符,()是函数调用运算符。自增自减运算符的前置和后置形式都可以重载。长度运算符sizeof、条件运算符: ?、成员选择符.和域解析运算符::不能被重载。

    2) 重载不能改变运算符的优先级和结合性。假设上一节的 complex 类中重载了+号和*号,并且 c1、c2、c3、c4 都是 complex 类的对象,那么下面的语句:

    c4 = c1 + c2 * c3;

    等价于:

    c4 = c1 + ( c2 * c3 );

    乘法的优先级仍然高于加法,并且它们仍然是二元运算符。

    3) 重载不会改变运算符的用法,原有有几个操作数、操作数在左边还是在右边,这些都不会改变。例如~号右边只有一个操作数,+号总是出现在两个操作数之间,重载后也必须如此。

    4) 运算符重载函数不能有默认的参数,否则就改变了运算符操作数的个数,这显然是错误的。

    5) 运算符重载函数既可以作为类的成员函数,也可以作为全局函数。

    将运算符重载函数作为类的成员函数时,二元运算符的参数只有一个,一元运算符不需要参数。之所以少一个参数,是因为这个参数是隐含的。

    例如,上节的 complex 类中重载了加法运算符:

    complex operator+(const complex & A) const;

    当执行:

    c3 = c1 + c2;

    会被转换为:

    c3 = c1.operator+(c2);

    通过 this 指针隐式的访问 c1 的成员变量。

    将运算符重载函数作为全局函数时,二元操作符就需要两个参数,一元操作符需要一个参数,而且其中必须有一个参数是对象,好让编译器区分这是程序员自定义的运算符,防止程序员修改用于内置类型的运算符的性质。

    例如,下面这样是不对的:

    1. int operator + (int a,int b){
    2. return (a-b);
    3. }

    +号原来是对两个数相加,现在企图通过重载使它的作用改为两个数相减, 如果允许这样重载的话,那么表达式4+3的结果是 7 还是 1 呢?显然,这是绝对禁止的。

    如果有两个参数,这两个参数可以都是对象,也可以一个是对象,一个是C ++内置类型的数据,例如:

    1. complex operator+(int a, complex &c){
    2. return complex(a+c.real, c.imag);
    3. }

    它的作用是使一个整数和一个复数相加。

    另外,将运算符重载函数作为全局函数时,一般都需要在类中将该函数声明为友元函数。原因很简单,该函数大部分情况下都需要使用类的 private 成员。

    上节的最后一个例子中,我们在全局范围内重载了+号,并在 complex 类中将运算符重载函数声明为友元函数,因为该函数使用到了 complex 类的 m_real 和 m_imag 两个成员变量,它们都是 private 属性的,默认不能在类的外部访问。

    6) 箭头运算符->、下标运算符[ ]、函数调用运算符( )、赋值运算符=只能以成员函数的形式重载。

    三、C++重载数学运算符

    四则运算符(+、-、*、/、+=、-=、*=、/=)和关系运算符(>、<、<=、>=、==、!=)都是数学运算符,它们在实际开发中非常常见,被重载的几率也很高,并且有着相似的重载格式。本节以复数类 Complex 为例对它们进行重载,重在演示运算符重载的语法以及规范。

    复数能够进行完整的四则运算,但不能进行完整的关系运算:我们只能判断两个复数是否相等,但不能比较它们的大小,所以不能对 >、<、<=、>= 进行重载。下面是具体的代码:

    1. #include <iostream>
    2. #include <cmath>
    3. using namespace std;
    4. //复数类
    5. class Complex{
    6. public: //构造函数
    7. Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ }
    8. public: //运算符重载
    9. //以全局函数的形式重载
    10. friend Complex operator+(const Complex &c1, const Complex &c2);
    11. friend Complex operator-(const Complex &c1, const Complex &c2);
    12. friend Complex operator*(const Complex &c1, const Complex &c2);
    13. friend Complex operator/(const Complex &c1, const Complex &c2);
    14. friend bool operator==(const Complex &c1, const Complex &c2);
    15. friend bool operator!=(const Complex &c1, const Complex &c2);
    16. //以成员函数的形式重载
    17. Complex & operator+=(const Complex &c);
    18. Complex & operator-=(const Complex &c);
    19. Complex & operator*=(const Complex &c);
    20. Complex & operator/=(const Complex &c);
    21. public: //成员函数
    22. double real() const{ return m_real; }
    23. double imag() const{ return m_imag; }
    24. private:
    25. double m_real; //实部
    26. double m_imag; //虚部
    27. };
    28. //重载+运算符
    29. Complex operator+(const Complex &c1, const Complex &c2){
    30. Complex c;
    31. c.m_real = c1.m_real + c2.m_real;
    32. c.m_imag = c1.m_imag + c2.m_imag;
    33. return c;
    34. }
    35. //重载-运算符
    36. Complex operator-(const Complex &c1, const Complex &c2){
    37. Complex c;
    38. c.m_real = c1.m_real - c2.m_real;
    39. c.m_imag = c1.m_imag - c2.m_imag;
    40. return c;
    41. }
    42. //重载*运算符 (a+bi) * (c+di) = (ac-bd) + (bc+ad)i
    43. Complex operator*(const Complex &c1, const Complex &c2){
    44. Complex c;
    45. c.m_real = c1.m_real * c2.m_real - c1.m_imag * c2.m_imag;
    46. c.m_imag = c1.m_imag * c2.m_real + c1.m_real * c2.m_imag;
    47. return c;
    48. }
    49. //重载/运算符 (a+bi) / (c+di) = [(ac+bd) / (c²+d²)] + [(bc-ad) / (c²+d²)]i
    50. Complex operator/(const Complex &c1, const Complex &c2){
    51. Complex c;
    52. c.m_real = (c1.m_real*c2.m_real + c1.m_imag*c2.m_imag) / (pow(c2.m_real, 2) + pow(c2.m_imag, 2));
    53. c.m_imag = (c1.m_imag*c2.m_real - c1.m_real*c2.m_imag) / (pow(c2.m_real, 2) + pow(c2.m_imag, 2));
    54. return c;
    55. }
    56. //重载==运算符
    57. bool operator==(const Complex &c1, const Complex &c2){
    58. if( c1.m_real == c2.m_real && c1.m_imag == c2.m_imag ){
    59. return true;
    60. }else{
    61. return false;
    62. }
    63. }
    64. //重载!=运算符
    65. bool operator!=(const Complex &c1, const Complex &c2){
    66. if( c1.m_real != c2.m_real || c1.m_imag != c2.m_imag ){
    67. return true;
    68. }else{
    69. return false;
    70. }
    71. }
    72. //重载+=运算符
    73. Complex & Complex::operator+=(const Complex &c){
    74. this->m_real += c.m_real;
    75. this->m_imag += c.m_imag;
    76. return *this;
    77. }
    78. //重载-=运算符
    79. Complex & Complex::operator-=(const Complex &c){
    80. this->m_real -= c.m_real;
    81. this->m_imag -= c.m_imag;
    82. return *this;
    83. }
    84. //重载*=运算符
    85. Complex & Complex::operator*=(const Complex &c){
    86. this->m_real = this->m_real * c.m_real - this->m_imag * c.m_imag;
    87. this->m_imag = this->m_imag * c.m_real + this->m_real * c.m_imag;
    88. return *this;
    89. }
    90. //重载/=运算符
    91. Complex & Complex::operator/=(const Complex &c){
    92. this->m_real = (this->m_real*c.m_real + this->m_imag*c.m_imag) / (pow(c.m_real, 2) + pow(c.m_imag, 2));
    93. this->m_imag = (this->m_imag*c.m_real - this->m_real*c.m_imag) / (pow(c.m_real, 2) + pow(c.m_imag, 2));
    94. return *this;
    95. }
    96. int main(){
    97. Complex c1(25, 35);
    98. Complex c2(10, 20);
    99. Complex c3(1, 2);
    100. Complex c4(4, 9);
    101. Complex c5(34, 6);
    102. Complex c6(80, 90);
    103. Complex c7 = c1 + c2;
    104. Complex c8 = c1 - c2;
    105. Complex c9 = c1 * c2;
    106. Complex c10 = c1 / c2;
    107. cout<<"c7 = "<<c7.real()<<" + "<<c7.imag()<<"i"<<endl;
    108. cout<<"c8 = "<<c8.real()<<" + "<<c8.imag()<<"i"<<endl;
    109. cout<<"c9 = "<<c9.real()<<" + "<<c9.imag()<<"i"<<endl;
    110. cout<<"c10 = "<<c10.real()<<" + "<<c10.imag()<<"i"<<endl;
    111. c3 += c1;
    112. c4 -= c2;
    113. c5 *= c2;
    114. c6 /= c2;
    115. cout<<"c3 = "<<c3.real()<<" + "<<c3.imag()<<"i"<<endl;
    116. cout<<"c4 = "<<c4.real()<<" + "<<c4.imag()<<"i"<<endl;
    117. cout<<"c5 = "<<c5.real()<<" + "<<c5.imag()<<"i"<<endl;
    118. cout<<"c6 = "<<c6.real()<<" + "<<c6.imag()<<"i"<<endl;
    119. if(c1 == c2){
    120. cout<<"c1 == c2"<<endl;
    121. }
    122. if(c1 != c2){
    123. cout<<"c1 != c2"<<endl;
    124. }
    125. return 0;
    126. }

    运行结果:
    c7 = 35 + 55i
    c8 = 15 + 15i
    c9 = -450 + 850i
    c10 = 1.9 + -0.3i
    c3 = 26 + 37i
    c4 = -6 + -11i
    c5 = 220 + 4460i
    c6 = 5.2 + 1.592i
    c1 != c2

    需要注意的是,我们以全局函数的形式重载了 +、-、*、/、==、!=,以成员函数的形式重载了 +=、-=、*=、/=,而且应该坚持这样做,不能一股脑都写作成员函数或者全局函数,具体原因我们将在下节讲解。

    四、C++重载>>和<<(输入输出运算符)

    在C++中,标准库本身已经对左移运算符<<和右移运算符>>分别进行了重载,使其能够用于不同数据的输入输出,但是输入输出的对象只能是 C++ 内置的数据类型(例如 bool、int、double 等)和标准库所包含的类类型(例如 string、complex、ofstream、ifstream 等)。

    如果我们自己定义了一种新的数据类型,需要用输入输出运算符去处理,那么就必须对它们进行重载。本节以前面的 complex 类为例来演示输入输出运算符的重载。

    其实 C++ 标准库已经提供了 complex 类,能够很好地支持复数运算,但是这里我们又自己定义了一个 complex 类,这样做仅仅是为了教学演示。

    本节要达到的目标是让复数的输入输出和 int、float 等基本类型一样简单。假设 num1、num2 是复数,那么输出形式就是:

    cout<<num1<<num2<<endl;

    输入形式就是:

    cin>>num1>>num2;

    cout 是 istream 类的对象,cin 是 ostream 类的对象,要想达到这个目标,就必须以全局函数(友元函数)的形式重载<<>>,否则就要修改标准库中的类,这显然不是我们所期望的。

    重载输入运算符>>

    下面我们以全局函数的形式重载>>,使它能够读入两个 double 类型的数据,并分别赋值给复数的实部和虚部:

    1. istream & operator>>(istream &in, complex &A){
    2. in >> A.m_real >> A.m_imag;
    3. return in;
    4. }

    istream 表示输入流,cin 是 istream 类的对象,只不过这个对象是在标准库中定义的。之所以返回 istream 类对象的引用,是为了能够连续读取复数,让代码书写更加漂亮,例如:

    complex c1, c2;
    cin>>c1>>c2;

    如果不返回引用,那就只能一个一个地读取了:

    complex c1, c2;
    cin>>c1;
    cin>>c2;

    另外,运算符重载函数中用到了 complex 类的 private 成员变量,必须在 complex 类中将该函数声明为友元函数:

    friend istream & operator>>(istream & in , complex &a);

    >>运算符可以按照下面的方式使用:

    complex c;
    cin>>c;

    当输入1.45 2.34↙后,这两个小数就分别成为对象 c 的实部和虚部了。cin>> c;这一语句其实可以理解为:

    operator<<(cin , c);

    重载输出运算符<<

    同样地,我们也可以模仿上面的形式对输出运算符>>进行重载,让它能够输出复数,请看下面的代码:

    1. ostream & operator<<(ostream &out, complex &A){
    2. out << A.m_real <<" + "<< A.m_imag <<" i ";
    3. return out;
    4. }

    ostream 表示输出流,cout 是 ostream 类的对象。由于采用了引用的方式进行参数传递,并且也返回了对象的引用,所以重载后的运算符可以实现连续输出。

    为了能够直接访问 complex 类的 private 成员变量,同样需要将该函数声明为 complex 类的友元函数:

    friend ostream & operator<<(ostream &out, complex &A);

    综合演示

    结合输入输出运算符的重载,重新实现 complex 类:

    1. #include <iostream>
    2. using namespace std;
    3. class complex{
    4. public:
    5. complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ };
    6. public:
    7. friend complex operator+(const complex & A, const complex & B);
    8. friend complex operator-(const complex & A, const complex & B);
    9. friend complex operator*(const complex & A, const complex & B);
    10. friend complex operator/(const complex & A, const complex & B);
    11. friend istream & operator>>(istream & in, complex & A);
    12. friend ostream & operator<<(ostream & out, complex & A);
    13. private:
    14. double m_real; //实部
    15. double m_imag; //虚部
    16. };
    17. //重载加法运算符
    18. complex operator+(const complex & A, const complex &B){
    19. complex C;
    20. C.m_real = A.m_real + B.m_real;
    21. C.m_imag = A.m_imag + B.m_imag;
    22. return C;
    23. }
    24. //重载减法运算符
    25. complex operator-(const complex & A, const complex &B){
    26. complex C;
    27. C.m_real = A.m_real - B.m_real;
    28. C.m_imag = A.m_imag - B.m_imag;
    29. return C;
    30. }
    31. //重载乘法运算符
    32. complex operator*(const complex & A, const complex &B){
    33. complex C;
    34. C.m_real = A.m_real * B.m_real - A.m_imag * B.m_imag;
    35. C.m_imag = A.m_imag * B.m_real + A.m_real * B.m_imag;
    36. return C;
    37. }
    38. //重载除法运算符
    39. complex operator/(const complex & A, const complex & B){
    40. complex C;
    41. double square = A.m_real * A.m_real + A.m_imag * A.m_imag;
    42. C.m_real = (A.m_real * B.m_real + A.m_imag * B.m_imag)/square;
    43. C.m_imag = (A.m_imag * B.m_real - A.m_real * B.m_imag)/square;
    44. return C;
    45. }
    46. //重载输入运算符
    47. istream & operator>>(istream & in, complex & A){
    48. in >> A.m_real >> A.m_imag;
    49. return in;
    50. }
    51. //重载输出运算符
    52. ostream & operator<<(ostream & out, complex & A){
    53. out << A.m_real <<" + "<< A.m_imag <<" i ";;
    54. return out;
    55. }
    56. int main(){
    57. complex c1, c2, c3;
    58. cin>>c1>>c2;
    59. c3 = c1 + c2;
    60. cout<<"c1 + c2 = "<<c3<<endl;
    61. c3 = c1 - c2;
    62. cout<<"c1 - c2 = "<<c3<<endl;
    63. c3 = c1 * c2;
    64. cout<<"c1 * c2 = "<<c3<<endl;
    65. c3 = c1 / c2;
    66. cout<<"c1 / c2 = "<<c3<<endl;
    67. return 0;
    68. }

    运行结果:
    2.4 3.6↙
    4.8 1.7↙
    c1 + c2 = 7.2 + 5.3 i
    c1 - c2 = -2.4 + 1.9 i
    c1 * c2 = 5.4 + 21.36 i
    c1 / c2 = 0.942308 + 0.705128 i

    五、C++重载[ ](下标运算符)

    C++ 规定,下标运算符[ ]必须以成员函数的形式进行重载。该重载函数在类中的声明格式如下:

    返回值类型 & operator[ ] (参数);

    或者:

    const 返回值类型 & operator[ ] (参数) const;

    使用第一种声明方式,[ ]不仅可以访问元素,还可以修改元素。使用第二种声明方式,[ ]只能访问而不能修改元素。在实际开发中,我们应该同时提供以上两种形式,这样做是为了适应 const 对象,因为通过 const 对象只能调用 const 成员函数,如果不提供第二种形式,那么将无法访问 const 对象的任何元素。

    下面我们通过一个具体的例子来演示如何重载[ ]。我们知道,有些较老的编译器不支持变长数组,例如 VC6.0、VS2010 等,这有时候会给编程带来不便,下面我们通过自定义的 Array 类来实现变长数组。

    1. #include <iostream>
    2. using namespace std;
    3. class Array{
    4. public:
    5. Array(int length = 0);
    6. ~Array();
    7. public:
    8. int & operator[](int i);
    9. const int & operator[](int i) const;
    10. public:
    11. int length() const { return m_length; }
    12. void display() const;
    13. private:
    14. int m_length; //数组长度
    15. int *m_p; //指向数组内存的指针
    16. };
    17. Array::Array(int length): m_length(length){
    18. if(length == 0){
    19. m_p = NULL;
    20. }else{
    21. m_p = new int[length];
    22. }
    23. }
    24. Array::~Array(){
    25. delete[] m_p;
    26. }
    27. int& Array::operator[](int i){
    28. return m_p[i];
    29. }
    30. const int & Array::operator[](int i) const{
    31. return m_p[i];
    32. }
    33. void Array::display() const{
    34. for(int i = 0; i < m_length; i++){
    35. if(i == m_length - 1){
    36. cout<<m_p[i]<<endl;
    37. }else{
    38. cout<<m_p[i]<<", ";
    39. }
    40. }
    41. }
    42. int main(){
    43. int n;
    44. cin>>n;
    45. Array A(n);
    46. for(int i = 0, len = A.length(); i < len; i++){
    47. A[i] = i * 5;
    48. }
    49. A.display();
    50. const Array B(n);
    51. cout<<B[n-1]<<endl; //访问最后一个元素
    52. return 0;
    53. }

    运行结果:
    5↙
    0, 5, 10, 15, 20
    33685536

    重载[ ]运算符以后,表达式arr[i]会被转换为:

    arr.operator[ ](i);

    需要说明的是,B 是 const 对象,如果 Array 类没有提供 const 版本的operator[ ],那么第 60 行代码将报错。虽然第 60 行代码只是读取对象的数据,并没有试图修改对象,但是它调用了非 const 版本的operator[ ],编译器不管实际上有没有修改对象,只要是调用了非 const 的成员函数,编译器就认为会修改对象(至少有这种风险)。

    六、C++重载++和--(自增自减运算符)

    自增++和自减--都是一元运算符,它的前置形式和后置形式都可以被重载。请看下面的例子:

    1. #include <iostream>
    2. #include <iomanip>
    3. using namespace std;
    4. //秒表类
    5. class stopwatch{
    6. public:
    7. stopwatch(): m_min(0), m_sec(0){ }
    8. public:
    9. void setzero(){ m_min = 0; m_sec = 0; }
    10. stopwatch run(); // 运行
    11. stopwatch operator++(); //++i,前置形式
    12. stopwatch operator++(int); //i++,后置形式
    13. friend ostream & operator<<( ostream &, const stopwatch &);
    14. private:
    15. int m_min; //分钟
    16. int m_sec; //秒钟
    17. };
    18. stopwatch stopwatch::run(){
    19. ++m_sec;
    20. if(m_sec == 60){
    21. m_min++;
    22. m_sec = 0;
    23. }
    24. return *this;
    25. }
    26. stopwatch stopwatch::operator++(){
    27. return run();
    28. }
    29. stopwatch stopwatch::operator++(int n){
    30. stopwatch s = *this;
    31. run();
    32. return s;
    33. }
    34. ostream &operator<<( ostream & out, const stopwatch & s){
    35. out<<setfill('0')<<setw(2)<<s.m_min<<":"<<setw(2)<<s.m_sec;
    36. return out;
    37. }
    38. int main(){
    39. stopwatch s1, s2;
    40. s1 = s2++;
    41. cout << "s1: "<< s1 <<endl;
    42. cout << "s2: "<< s2 <<endl;
    43. s1.setzero();
    44. s2.setzero();
    45. s1 = ++s2;
    46. cout << "s1: "<< s1 <<endl;
    47. cout << "s2: "<< s2 <<endl;
    48. return 0;
    49. }

    运行结果:
    s1: 00:00
    s2: 00:01
    s1: 00:01
    s2: 00:01

    上面的代码定义了一个简单的秒表类,m_min 表示分钟,m_sec 表示秒钟,setzero() 函数用于秒表清零,run() 函数是用来描述秒针前进一秒的动作,接下来是三个运算符重载函数。

    先来看一下 run() 函数的实现,run() 函数一开始让秒针自增,如果此时自增结果等于60了,则应该进位,分钟加1,秒针置零。

    operator++() 函数实现自增的前置形式,直接返回 run() 函数运行结果即可。

    operator++ (int n) 函数实现自增的后置形式,返回值是对象本身,但是之后再次使用该对象时,对象自增了,所以在该函数的函数体中,先将对象保存,然后调用一次 run() 函数,之后再将先前保存的对象返回。在这个函数中参数n是没有任何意义的,它的存在只是为了区分是前置形式还是后置形式。

    自减运算符的重载与上面类似,这里不再赘述。

    七、C++重载new和delete运算符

    内存管理运算符 new、new[]、delete 和 delete[] 也可以进行重载,其重载形式既可以是类的成员函数,也可以是全局函数。一般情况下,内建的内存管理运算符就够用了,只有在需要自己管理内存时才会重载。

    以成员函数的形式重载 new 运算符:

    void * className::operator new( size_t size ){
        //TODO:
    }

    以全局函数的形式重载 new 运算符:

    void * operator new( size_t size ){
        //TODO:
    }

    两种重载形式的返回值相同,都是void *类型,并且都有一个参数,为size_t类型。在重载 new 或 new[] 时,无论是作为成员函数还是作为全局函数,它的第一个参数必须是 size_t 类型。size_t 表示的是要分配空间的大小,对于 new[] 的重载函数而言,size_t 则表示所需要分配的所有空间的总和。

    size_t 在头文件 <cstdio> 中被定义为typedef unsigned int size_t;,也就是无符号整型。

    当然,重载函数也可以有其他参数,但都必须有默认值,并且第一个参数的类型必须是 size_t。

    同样的,delete 运算符也有两种重载形式。以类的成员函数的形式进行重载:

    void className::operator delete( void *ptr){
        //TODO:
    }

    以全局函数的形式进行重载:

    void operator delete( void *ptr){
        //TODO:
    }

    两种重载形式的返回值都是 void 类型,并且都必须有一个 void 类型的指针作为参数,该指针指向需要释放的内存空间。

    当我们以类的成员函数的形式重载了new 和 delete 操作符,其使用方法如下:

    1. C * c = new C; //分配内存空间
    2. //TODO:
    3. delete c; //释放内存空间

    如果类中没有定义 new 和 delete 的重载函数,那么会自动调用内建的 new 和 delete 运算符。

  • 相关阅读:
    数据结构-树与二叉树-思维导图
    The last packet successfully received from the server was 2,272 milliseconds ago. The last packet sent successfully to the server was 2,258 milliseconds ago.
    idea连接mysql报错Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property
    redis学习笔记
    AJAX校验注册用户名是否存在
    AJAX学习笔记
    JSON学习笔记
    JQuery基础知识学习笔记
    Filter、Listener学习笔记
    三层架构学习笔记
  • 原文地址:https://www.cnblogs.com/fnlingnzb-learner/p/7991735.html
Copyright © 2011-2022 走看看