C++類或結構作為map的key值


1.只有重載<的類或者結構才能作為map的key值。
string可以作為key值是因為string重載了<
2.如果不重載<會提示如下錯誤:
error C2676: 二進制“<”: “const C”不定義該運算符或到預定義運算符可接收的類型的轉換

3.重載<但是沒有實現會提示如下錯誤:
Expression: invalid operator<
比如bool operator < (const C &c) const{return true;}

#include < string>
#include <map>

using  namespace std;

//  重載<的類或結構才能作為map的key值
class C
{
public:
     int i;
     string str;
     bool  operator < ( const C &c)  const
    {
         return i < c.i;
    }
};

void main()
{
    map<C, int> mapC;
    C c0;
    c0.i =  0;
    c0.str =  " str1 ";
    mapC.insert(pair<C, int>(c0, 0));
    C c1;
    c1.i =  1;
    c1.str =  " str2 ";
    mapC.insert(pair<C, int>(c1, 1));
    
     if(c0 < c1)
         int iVal = mapC[c1];

     //  string可以作為map的key,因為重載了<
     string str1 =  " str1 ",str2 =  " str2 ";
     if(str1 < str2)  //  "str2"是大於"str1"的
    {
         int n =  0;
    }
}
/*  如果不重載<會提示如下錯誤:
 * error C2676: 二進制“<”: “const C”不定義該運算符或到預定義運算符可接收的類型的轉換
 * 重載<但是沒有實現會提示如下錯誤:
 * Expression: invalid operator<
 * 比如bool operator < (const C &c) const{return true;}
 
*/
url: http://greatverve.cnblogs.com/archive/2012/11/05/cpp-class-map-key.html 
補充: C++運算符重載

運算符重載的基礎就是運算符重載函數。所以今天主要講的是運算符重載函數。

  1.運算符重載是對已有的運算符賦予多重含義,使同一個運算符作用域不同類型的數據導致不同行為的發生。比如

復制代碼
1 int i;
2 int i1=10,i2=10;
3 i=i1+i2;
4 std::cout<<"i1+i2="<<i<<std::endl;
5
6 double d;
7 double d1=20,d2=20;
8 d=d1+d2;
9 std::cout<<"d1+d2="<<d<<std::endl;
復制代碼

在這個程序里"+"既完成兩個整形數的加法運算,又完成了雙精度型的加法運算。為什么同一個運算符"+"可以用於完成不同類型的數據的加法運算?這是因為C++針對預定義基本數據類型已經對"+"運算符做了適當的重載。在編譯程序編譯不同類型數據的加法表達式時,會自動調用相應類型的加法運算符重載函數。但是C++中所提供的預定義的基本數據類型畢竟是有限的,在解決一些實際的問題時,往往需要用戶自定義數據類型。比如高中數學里所提到的復數:

復制代碼
 1 class Complex //復數類
2 {
3 public:
4 double real;//實數
5 double imag;//虛數
6 Complex(double real=0,double imag=0)
7 {
8 this->real=real;
9 this->imag=imag;
10 }
11 }
復制代碼

假如我們建立兩個復數,並用"+"運算符讓它們直接相加:

1 Complex com1(10,10),com2(20,20),sum;
2 sum=com1+com2;

那么會提示沒有與這些操作數匹配的 "+" 運算符的錯誤。這是因為Complex類類型不是預定義類型,系統沒用對該類型的數據進行加法運算符函數的重載。C++就為運算符重載提供了一種方法,即運算符重載函數。其函數名字規定為operator后緊跟重載運算符。比如:operator+(),operator*()等。現在我們給上述程序聲明一個加法運算符的重載函數用於完成復數的加法運算:

View Code
復制代碼
 1 #include "stdafx.h"
2 #include <iostream>
3
4 class Complex //復數類
5 {
6 public:
7 double real;//實數
8 double imag;//虛數
9 Complex(double real=0,double imag=0)
10 {
11 this->real=real;
12 this->imag=imag;
13 }
14 };
15
16 Complex operator+(Complex com1,Complex com2)//運算符重載函數
17 {
18 return Complex(com1.real+com2.real,com1.imag+com2.imag);
19 }
20
21 int main()
22 {
23 Complex com1(10,10),com2(20,20),sum;
24 sum=com1+com2;//或sum=operator+(com1,com2)
25
26 std::cout<<"sum的實數部分為"<<sum.real<<std::endl;
27 std::cout<<"sum的虛數部分為"<<sum.imag<<"i"<<std::endl;
28
29 return0;
30 }
復制代碼

結果:

在上述示例代碼中,調用運算符重載函數時,也可以以operator+(com1,com2)的形式來調用,實際上com1+com2在程序解釋時也是轉化成前者一樣的形式。但是直接用com1+com2的形式更加符合人的書寫習慣。

  2.上述示例中的運算符重載函數是不屬於任何的類,是全局的函數。因為在Complex類(復數類)中的數據成員是公有的性質,所以運算符重載函數可以訪問。但如果定義為私有的呢,那該怎么辦。其實,在實際的運算符重載函數聲明當中,要不定義其為要操作類的成員函數或類的友元函數

  (1)運算符重載函數作為類的友元函數的形式:

  class 類名

  {

    friend 返回類型 operator運算符(形參表);

  }

  類外定義格式:

  返回類型 operator運算符(參數表)

  {

    函數體

  }

友元函數重載雙目運算符(有兩個操作數,通常在運算符的左右兩則),參數表中的個數為兩個。若是重載單目運算符(只有一個操作數),則參數表中只有一參數。

i.友元函數重載雙目運算符(+):

View Code
復制代碼
 1 #include "stdafx.h"
2 #include <iostream>
3
4 class Complex //復數類
5 {
6 private://私有
7 double real;//實數
8 double imag;//虛數
9 public:
10 Complex(double real=0,double imag=0)
11 {
12 this->real=real;
13 this->imag=imag;
14 }
15 friend Complex operator+(Complex com1,Complex com2);//友元函數重載雙目運算符+
16 void showSum();
17 };
18
19
20 Complex operator+(Complex com1,Complex com2)//友元運算符重載函數
21 {
22 return Complex(com1.real+com2.real,com1.imag+com2.imag);
23 }
24
25 void Complex::showSum()
26 {
27 std::cout<<real;
28 if(imag>0)
29 std::cout<<"+";
30 if(imag!=0)
31 std::cout<<imag<<"i"<<std::endl;
32 }
33
34 int main()
35 {
36 Complex com1(10,10),com2(20,-20),sum;
37 sum=com1+com2;//或sum=operator+(com1,com2)
38 sum.showSum();//輸出復數相加結果
39
40 return0;
41 }
復制代碼

結果:

ii.友元函數重載單目運算符(++):

View Code
復制代碼
 1 #include "stdafx.h"
2 #include <iostream>
3
4 class Point//坐標類
5 {
6 private:
7 int x;
8 int y;
9 public:
10 Point(int x,int y)
11 {
12 this->x=x;
13 this->y=y;
14 }
15 friend voidoperator++(Point& point);//友元函數重載單目運算符++
16 void showPoint();
17 };
18
19 voidoperator++(Point& point)//友元運算符重載函數
20 {
21 ++point.x;
22 ++point.y;
23 }
24
25 void Point::showPoint()
26 {
27 std::cout<<"("<<x<<","<<y<<")"<<std::endl;
28 }
29
30 int main()
31 {
32 Point point(10,10);
33 ++point;//或operator++(point)
34 point.showPoint();//輸出坐標值
35
36 return0;
37 }
復制代碼

結果:

運算符重載函數可以返回任何類型,甚至是void,但通常返回類型都與它所操作的類類型一樣,這樣可以使運算符使用在復雜的表達式中。比如把上述雙目運算符重載函數示例代碼中main()主函數里的com1+com2改為com1+com2+com2,那么結果又會不一樣了。像賦值運算符=、下標運算符[]、函數調用運算符()等是不能被定義為友元運算符重載函數。同一個運算符可以定義多個運算符重載函數來進行不同的操作。

  (2)運算符重載函數作為類的成員函數的形式:

  class 類名

  {

    返回類型 operator 運算符(形參表);

  }

   類外定義格式:

  返回類型 類名:: operator 運算符(形參表)

  {

    函數體;

  }

對於成員函數重載運算符而言,雙目運算符的參數表中僅有一個參數,而單目則無參數。同樣的是重載,為什么和友元函數在參數的個數上會有所區別的。原因在於友元函數,沒有this指針

i.成員函數重載雙目運算符(+):

View Code
復制代碼
 1 #include "stdafx.h"
2 #include <iostream>
3
4 class Complex //復數類
5 {
6 private://私有
7 double real;//實數
8 double imag;//虛數
9 public:
10 Complex(double real=0,double imag=0)
11 {
12 this->real=real;
13 this->imag=imag;
14 }
15 Complex operator+(Complex com1);//成員函數重載雙目運算符+
16 void showSum();
17 };
18
19
20 Complex Complex::operator+(Complex com1)
21 {
22 return Complex(real+com1.real,imag+com1.imag);
23 }
24
25 void Complex::showSum()
26 {
27 std::cout<<real;
28 if(imag>0)
29 std::cout<<"+";
30 if(imag!=0)
31 std::cout<<imag<<"i"<<std::endl;
32 }
33
34
35 int main()
36 {
37 Complex com1(10,10),com2(20,-20),sum;
38 sum=com1+com2;//或sum=com1.operator+(com2)
39 sum.showSum();//輸出復數相加結果
40 return0;
41 }
復制代碼

對於雙目運算符而言,運算符重載函數的形參中僅為一個參數,它作為運算符的右操作數(如com2對象),而當前對象作為左操作數(如:上述中的com1對象),它是通過this指針隱含傳遞給成員運算符重載函數的

ii.成員函數重載單目運算符(++):

View Code
復制代碼
 1 #include "stdafx.h"
2 #include <iostream>
3
4
5 class Point//坐標類
6 {
7 private:
8 int x;
9 int y;
10 public:
11 Point(int x,int y)
12 {
13 this->x=x;
14 this->y=y;
15 }
16 voidoperator++();//成員函數重載雙目運算符++
17 void showPoint();
18 };
19
20
21 void Point::operator++()
22 {
23 ++x;
24 ++y;
25 }
26
27
28 void Point::showPoint()
29 {
30 std::cout<<"("<<x<<","<<y<<")"<<std::endl;
31 }
32
33 int main()
34 {
35 Point point(10,10);
36 ++point;//或point.operator++()
37 point.showPoint();//輸出坐標值
38
39 return0;
40 }
復制代碼

對於單目運算符而言,當前對象作為運算符的操作數

  在運算符重載運用時應該注意以下幾個問題:(1)C++中只能對已有的C++運算符進行重載,不允許用戶自己定義新的運算符;(2)C++中絕大部分的運算符可重載,除了成員訪問運算符.,成員指針訪問運算符.*,作用域運算符::,長度運算符sizeof以及條件運算符?:;(3)重載后不能改變運算符的操作對象(操作數)的個數。如:"+"是實現兩個操作數的運算符,重載后仍然為雙目運算符;(4)重載不能改變運算符原有的優先級;(5)重載不能改變運算符原有結合的特性。比如:z=x/y*a,執行時是先做左結合的運算x/y,重載后也是如此,不會變成先做右結合y*a;(6)運算符重載不能全部是C++中預定義的基本數據,這樣做的目的是為了防止用戶修改用於基本類型數據的運算符性質;(7)從上述的示例中可以看到雙目運算符可以被重載為友元函數也可以重載為成員函數,但有一種情況,只能使用友元函數,是什么情況呢?我舉個例子: 

復制代碼
 1 class Complex //復數類
2 {
3 private://私有
4 double real;//實數
5 double imag;//虛數
6 public:
7 Complex(double real=0,double imag=0)
8 {
9 this->real=real;
10 this->imag=imag;
11 }
12 Complex operator+(int x);
13 };
14
15 Complex Complex::operator+(int x)
16 {
17 return Complex(real+x,imag);
18 }
19
20 int main()
21 {
22 Complex com1(5,10),total;
23 total=com1+5;
24
25 return0;
26 }
復制代碼

如果我們把上述main()主函數實現部分里的total=com1+5改為total=5+com1;那么程序就會報錯(沒有與這些操作數匹配的 "+" 運算符),因為左操作數5不是該復數類的對象,不能調用相應的成員函數Complex operator+(int x),所以編譯錯誤。但如果我們定義一下兩個友元函數就能解決上述的問題:

  friend Complex operator+(Complex com1,int x);

  friend Complex operator+(int x,Complex com1);

  3.最后還是一樣,我將用一個示例來總結一下今天所講的內容(開發工具:vs2010): 

View Code
復制代碼
  1 #include "stdafx.h"
2 #include <iostream>
3
4 class Complex //復數類
5 {
6 private://私有
7 double real;//實數
8 double imag;//虛數
9 public:
10 Complex(double real=0,double imag=0)
11 {
12 this->real=real;
13 this->imag=imag;
14 }
15 Complex operator+(Complex com1);//成員函數重載雙目運算符+
16 //或friend Complex operator+(Complex com1,Complex com2);//友元函數重載雙目運算符+
17 friend Complex operator+(Complex com1,int x);//友元函數重載雙目運算符+
18 //或Complex operator+(int x);
19 friend Complex operator+(int x,Complex com1);//友元函數重載雙目運算符+
20 void showSum();
21 };
22
23
24 Complex Complex::operator+(Complex com1)
25 {
26 return Complex(real+com1.real,imag+com1.imag);
27 }
28
29 Complex operator+(Complex com1,int x)//左操作數類型為復數,右操作數的類型為整數
30 {
31 return Complex(com1.real+x,com1.imag);
32 }
33
34 Complex operator+(int x,Complex com1)//左操作數類型為整數,右操作數的類型為復數
35 {
36 return Complex(x+com1.real,com1.imag);
37 }
38
39 void Complex::showSum()
40 {
41 std::cout<<real;
42 if(imag>0)
43 std::cout<<"+";
44 if(imag!=0)
45 std::cout<<imag<<"i"<<std::endl;
46 }
47
48 class Point//坐標類
49 {
50 private:
51 int x;
52 int y;
53 public:
54 Point(int x,int y)
55 {
56 this->x=x;
57 this->y=y;
58 }
59 friend voidoperator++(Point& point);//友元函數重載單目運算符++
60 Point operator++();//成員函數重載雙目運算符++
61 void showPoint();
62 };
63
64 voidoperator++(Point& point)//友元運算符重載函數
65 {
66 ++point.x;
67 ++point.y;
68 }
69
70 Point Point::operator++()
71 {
72 ++x;
73 ++y;
74 return*this;//返回當前對象
75 }
76
77
78 void Point::showPoint()
79 {
80 std::cout<<"("<<x<<","<<y<<")"<<std::endl;
81 }
82
83 int main()
84 {
85 //兩個復數相加
86 std::cout<<"兩個復數相加:"<<std::endl;
87
88 Complex com1(10,10),com2(20,-20),sum;
89 sum=com1+com2;//或sum=com1.operator+(com2)
90 std::cout<<"(10+10i)+(20-20i)=";
91 sum.showSum();//輸出復數相加結果
92
93 //三個復數相加
94 std::cout<<"三個復數相加:"<<std::endl;
95
96 sum=com1+com2+com2;
97 std::cout<<"(10+10i)+(20-20i)+(20-20i)=";
98 sum.showSum();
99
100 //整數和復數相加
101 std::cout<<"整數和復數相加:"<<std::endl;
102
103 Complex com3(5,10),total;
104 total=com3+5;//或total=operator+(com1,5);
105 std::cout<<"(5+10i)+5=";
106 total.showSum();
107
108 total=5+com3;//或total=operator+(5,com1);
109 //只能用友元函數來重載運算符
110 std::cout<<"5+(5+10i)=";
111 total.showSum();
112
113 //單目運算符++重載
114 std::cout<<"單目運算符++重載:"<<std::endl;
115
116 //注意:下述實現部分不能只用一個++point會造成二義性
117 Point point(10,10);
118 //調用友元函數
119 operator++(point);//或++point
120 std::cout<<"調用友元函數:++(10,10)=";
121 point.showPoint();//輸出坐標值
122
123 //調用成員函數
124 point=point.operator++();//或++point;
125 std::cout<<"調用成員函數:++(10,10)=";
126 point.showPoint();
127
128 return0;
129 }
復制代碼

結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM