將會學到的內容:ios
函數定義分類:c++
1. 全局函數 2. 成員函數
例子:數組
class Coordinate { friend void printXY(Coordinate &c); public: Coordinate(int x,int y); private: int m_iX; int m_iY; }
關鍵字friend + 聲明友元函數(對象的引用或指針)ide
由於咱們在main函數中想使用printxy來調用座標類的私有數據成員。
前提是咱們須要在被調用的座標類中聲明該函數爲友元函數。函數
友元成員函數定義在類中,並把該函數聲明爲另一個類的友元函數。this
class Coordinate { friend void Circle::printXY(Coordinate &c); public: Coordinate(int x,int y); private: int m_iX; int m_iY; }
此時的printXY並非一個全局函數。而是一個Circle類中的成員函數。
也就是如今Circle的成員函數想使用座標類的私有數據,那麼咱們就要去Coordinate中去聲明。編碼
class Circle { public: void printXY(Coordinate &c) { cout << c.m_iX << c.m_iY; } } int main() { Coordinate coor(3,5); Circle circle; circle.printXY(coor); return 0; }
友元函數的風險: 破壞了Coordinate的封裝性。spa
2-2-FriendFunctionGlobal3d
Time.h指針
#ifndef TIME_H #define TIME_H #include <iostream> using namespace std; class Time { friend void printTime(Time &t);//重點 public: Time(int hour,int min,int sec); private: int m_iHour; int m_iMinute; int m_iSecond; }; #endif
Time.cpp
#include "Time.h" Time::Time(int hour, int min, int sec) { m_iHour = hour; m_iMinute = min; m_iSecond = sec; }
main.cpp
#include <iostream> #include <stdlib.h> #include "Time.h" using namespace std; void printTime(Time &t); int main() { Time t(6, 34, 35); printTime(t); system("pause"); return 0; } void printTime(Time &t) { cout << t.m_iHour << endl; // Time::m_iHour」: 沒法訪問 private 成員(在「Time」類中聲明) cout << t.m_iMinute << endl; cout << t.m_iSecond << endl; }
如上圖,看到是能夠訪問到t內部的私有數據成員。
2-2-FriendMemberFunction
Time.h
#ifndef TIME_H #define TIME_H #include "Match.h" #include <iostream> using namespace std; class Time { friend void Match::printTime(Time &t); //重點,建議寫在最外面。可是放在public,private都不影響。 public: Time(int hour,int min,int sec); private: int m_iHour; int m_iMinute; int m_iSecond; }; #endif
Time.cpp
#include "Time.h" Time::Time(int hour, int min, int sec) { m_iHour = hour; m_iMinute = min; m_iSecond = sec; }
Match.h
#ifndef MATCH_H #define MATCH_H class Time;//聲明有這樣一個類 class Match { public: void printTime(Time &t);// }; #endif
Match.cpp
#include "Match.h" #include "Time.h" #include <iostream> using namespace std; void Match::printTime(Time &t) { cout << t.m_iHour << ":" << t.m_iMinute << ":" << t.m_iSecond << endl; }
main.cpp
#include <iostream> #include <stdlib.h> #include "Time.h" #include "Match.h" using namespace std; int main() { Time t(6, 34, 35); Match m; m.printTime(t); system("pause"); return 0; }
Match的printTime函數想要用t裏面的私有數據,因此必須去向Time申請:也就是Time類須要聲明friend void Match::printTime(Time &t);
,Match的這個方法才能夠訪問它。
而Match由於要訪問到Time內部的數據,因此Match要聲明Time類:class Time;
友元函數的聲明能夠寫在public,private,類內全局均可以。但建議寫在類最前面。
定義Coordinate類,並將全局display函數聲明爲Coordinate類的友元函數
Coordinate類數據成員m_iX
和m_iY
display函數用於顯示m_iX
和m_iY
#include <iostream> using namespace std; /** * 定義Coordinate類 * 友元函數:display * 數據成員:m_iX、m_iY */ class Coordinate { // 友元函數 friend void display(Coordinate &coor); public: Coordinate(int x, int y) { m_iX = x; m_iY = y; } public: int m_iX; int m_iY; }; /** * display函數用於顯示m_iX、m_iY的值 */ void display(Coordinate &coor) { cout << "m_iX:" << coor.m_iX << endl; cout << "m_iY:" << coor.m_iY << endl; } int main(void) { // 實例化Coordinate對象 Coordinate coor(0,0); // 調用display函數 display(coor); return 0; }
class Circle;//聲明類的存在 class Coordinate { friend Circle;//聲明友元類。 public: Coordinate(int x,int y) private: int m_iX; int m_iY; }
class Circle { public: void printXY() { cout << m_coor.m_iX << m_coor.m_iY; } private: Coordinate m_coor; // 聲明他要用到的對象 }
任何Circle的成員函數均可以使用這個對象。
對於友元的注意事項
- 友元關係不可傳遞 (b是a的朋友,c是b的朋友,c不必定是a的朋友)
友元只是封裝的補充(不得已的作法, 破壞了封裝性): 定向的暴露。
2-5-FriendClass
Time.h
#ifndef TIME_H #define TIME_H class Match;// class Time { friend Match;// 聲明本身友元 public: Time(int hour,int min,int sec); private: void printTime(); int m_iHour; int m_iMinute; int m_iSecond; }; #endif
Time.cpp
#include "Time.h" #include <iostream> using namespace std; Time::Time(int hour, int min, int sec) { m_iHour = hour; m_iMinute = min; m_iSecond = sec; } void Time::printTime() { cout << m_iHour << "時" << m_iMinute << "分" << "秒" << endl; }
Match.h
#ifndef MATCH_H #define MATCH_H #include "Time.h" class Match { public: Match(int hour,int min,int sec); void testTime(); private: Time m_tTimer; // 聲明朋友存在 }; #endif
Match.cpp
#include "Match.h" #include <iostream> using namespace std; Match::Match(int hour, int min, int sec):m_tTimer(hour, min, sec) { } void Match::testTime() { m_tTimer.printTime(); cout << m_tTimer.m_iHour << ":" << m_tTimer.m_iMinute << ":" << m_tTimer.m_iSecond << endl; }
main.cpp
#include <iostream> #include <stdlib.h> #include "Time.h" #include "Match.h" using namespace std; int main() { Match m(6, 30, 50); m.testTime(); system("pause"); return 0; }
由於Time.h中聲明瞭友元類
class Match; friend Match;// 聲明本身友元
定義Time類,數據成員:m_iHour, m_iMinute,m_iSecond 成員函數:構造函數
定義Watch類,數據成員:m_tTime, 成員函數:構造函數,display用於顯示時間
Time類是Watch類的友元(Watch是Time友元類)
注:因爲編譯器不一樣,友元類有兩種寫法.
1. friend class 類名; 2. friend 類名;
若是對象A中有對象成員B,對象B沒有默認構造函數(也就是有參數傳遞,那麼對象A必須在初始化列表中初始化對象B。
#include <iostream> using namespace std; class Watch; /** * 定義Time類 * 數據成員:m_iHour, m_iMinute,m_iSecond * 成員函數:構造函數 * 友元類:Watch */ class Time { // 友元類 friend class Watch; public: Time(int hour, int min, int sec) { m_iHour = hour; m_iMinute = min; m_iSecond = sec; } public: int m_iHour; int m_iMinute; int m_iSecond; }; /** * 定義Watch類 * 數據成員:m_tTime * 成員函數:構造函數 * display用於顯示時間 */ class Watch { public: Watch(Time &t):m_tTime(t) { } void display() { cout << m_tTime.m_iHour << endl; cout << m_tTime.m_iMinute << endl; cout << m_tTime.m_iSecond << endl; } public: Time m_tTime; }; int main() { Time t(6, 30, 20); Watch w(t); w.display(); return 0; }
這裏要在Watch的構造函數中,將數據成員m_tTime填入Time的引用。
前面介紹過了:
關鍵字:
static: 靜態數據成員 & 靜態的成員函數
舉個例子:
class Tank { public: Tank(){s_iCount++;} ~Tank(){s_iCount--;} static int getCount(){ return s_iCount;} static int s_iCount; private: string m_strCode; int Tank::s_iCount = 0; //靜態數據成員的單獨初始化 }
在本來的普通數據成員前面加上關鍵字static,就能夠成爲靜態數據成員。
同理,在普通的成員函數前面加上關鍵字static,就能夠成爲靜態成員函數。
坦克大戰中, 本身方坦克數量多就會很英勇,本身方坦克少就很懦弱。
這時咱們須要讓全部的坦克對象能知道本身方有多少坦克。
構造方法中坦克數量++,析構函數中坦克數量--;對於每個坦克均可以經過訪問這個變量知道本身方還有多少坦克。
兩種訪問方法:
int main() { cout << Tank::getCount() <<endl; cout << Tank::s_iCount <<endl; Tank tank; cout << tank.getCount() <<endl; cout << tank.s_iCount << endl; return 0; }
內存中靜態數據成員和普通數據成員的區別。
Tank實例化出多個對象, 那麼普通數據成員code就會一個一個的誕生。
在這四個對象誕生以前, s_iCount就已經誕生了, 有且僅有這一個。
對象(孫子)都沒有出生,你仍是爺爺輩的人,就不能用孫子的錢。
class Tank { public: void fire(); static int getCount(); private: string m_strCode; static int s_iCount; }
當咱們經過fire去調用普通和靜態成員。
// 隱形的this指針 void fire(Tank *this) { this -> m_strCode = "01"; s_iCount = 0; } // 靜態成員函數,不會傳入this指針 static int getCount() { m_strCode = "01"; // 並不會傳入this指針。 // 並不能肯定是哪一個對象的成員了, return s_iCount; }
注意事項
sizeof求對象的大小,不會包含靜態數據成員大小。
3-2-StaticMemberFunction
Tank.h
#ifndef TANK_H #define TANK_H class Tank { public: Tank(char code); ~Tank(); void fire(); static int getCount(); private: static int s_iCount; char m_cCode; }; #endif
Tank.cpp
#include <iostream> #include "Tank.h" using namespace std; int Tank::s_iCount = 10; //構造函數以外,單獨初始化 Tank::Tank(char code) { m_cCode = code; s_iCount++; cout << "tank" << endl; } Tank::~Tank() { s_iCount--; cout << "~Tank()" << endl; } void Tank::fire() { cout << "Tank--fire" << endl; } int Tank::getCount() //聲明時添加static,定義時與普通一致 { return s_iCount; }
main.cpp
#include "Tank.h" #include <stdlib.h> #include <iostream> using namespace std; int main() { cout << Tank::getCount() << endl; //在類實例化以前就能使用 Tank t1('A'); cout << Tank::getCount() << endl; //初值10變成11 cout << t1.getCount() << endl; // 堆上實例化本身管理內存 Tank *p = new Tank('B'); cout << Tank::getCount() << endl; Tank *q = new Tank('C'); cout << q->getCount() << endl; delete p; delete q; cout << Tank::getCount() << endl; system("pause"); return 0; }
運行結果:
提醒1: 靜態的成員函數可否加上Const關鍵字。
static int getCount() const; //錯誤,原本是給this指針加const,如今沒有指針了。 // 報錯: 靜態成員函數上不容許修飾符
在普通成員函數中調用靜態成員函數
void Tank::fire() { getCount(); cout << "Tank--fire" << endl; }
普通成員函數中調用靜態成員函數,是能夠正常調用的。
在靜態成員函數中調用普通成員函數。
int Tank::getCount() //聲明時添加static。定義時普通 { fire(); //錯誤 m_cCode = 'C'; // 錯誤 // 報錯: 對非靜態成員「Tank::m_cCode」的非法引用 return s_iCount; }
非靜態成員函數的非法調用
給原有的運算符賦予新功能
本來+
是作數字相加操做,重載爲字符串拼接。
舉個栗子:
int main() { string str1("mtian"); string str2("yan"); string str3 = str1 + "" + str2; cout << str3 <<endl; return 0; }
上述代碼中=
, +
, <<
都作了重載
int main(void) { Coordinate coor1(1,3); Coordinate coor2(2,5); Coordinate coor3(0,0); coor3 = coor1 + coor2; cout << coor3 << endl; return 0; }
上述代碼中=
, +
, <<
都作了重載.能夠直接輸出座標。
運算符重載的本質:函數重載
定義運算符重載的關鍵字
operator
++
符號的重載一元運算符: 只與一個操做數運算。
-
(負號)的重載:
成員函數重載
class Coordinate { public: Coordinate(int x,int y); Coordinate& operator-();// 負號成員函數重載 private: int m_iX; int m_iY; } //實現: 隱形this指針 Coordinate& Coordinate::operator-() //隱藏的參數 { m_iX = -m_iX; m_iY = -m_iY; return *this; }
使用時
int main() { Coordinate coor1(3,5); -coor1; //coor1.operator-(); return 0; }
class Coordinate { friend Coordinate& operator-(Coordinate &coor); // 使用友元聲明全局函數 public: Coordinate(int x,int y); Coordinate& operator-();// private: int m_iX; int m_iY; } //實現 Coordinate& operator-(Coordinate &coor) { coor.m_iX = -coor.m_iX; coor.m_iY = -coor.m_iY; return *this; } //調用 int main() { Coordinate coor1(3,5); -coor1; //operator-(cool); return 0; }
成員函數重載與友元函數重載的區別。
operator-(cool)
:友元函數
coor1.operator-();
:成員函數++符號的重載:
++
符號重載++
符號重載++
運算符前置重載
class Coordinate { public: Coordinate(int x,int y); Coordinate& operator++(); //前置++ & 成員函數 private: int m_iX; int m_iY; } //定義實現 Coordinate& Coordinate::operator++() { m_iX++; m_iY++; return *this; } //使用 int main() { Coordinate coor1(3,5); ++coor1; //coor1.operator++() return 0; }
重載後置++
class Coordinate { public: Coordinate(int x,int y); Coordinate operator++(int);//後置++ //1. 返回的對象爲對象。 //2. 傳入參數int。int沒有任何用。只是爲了標識。 private: int m_iX; int m_iY; } Coordinate operator++(int) { Coordinate old(*this); //保存原來的值 m_iX++; m_iY++; return old; } int main() { Coordinate coor1(3,5); coor1++; //coor1.operator(0); return 0; }
4-2-UnaryOperatorOverload
Coordinate.h
#ifndef COORDINATE_H #define COORDINATE_H #include <iostream> using namespace std; class Coordinate { public: Coordinate(int x,int y); Coordinate & operator-(); // 聲明運算符重載 int getX(); int getY(); private: int m_iX; int m_iY; }; #endif
Coordinate.cpp
#include "Coordinate.h" Coordinate::Coordinate(int x, int y) { m_iX = x; m_iY = y; } int Coordinate::getX() { return m_iX; } int Coordinate::getY() { return m_iY; } // 運算符重載實現 Coordinate &Coordinate::operator-() { m_iX = -m_iX; this->m_iY = -this->m_iY; return *this; }
main.cpp
#include "Coordinate.h" #include <iostream> #include <stdlib.h> using namespace std; int main() { Coordinate coor1(1, 3); cout << coor1.getX() << "," << coor1.getY() << endl; -coor1; //coor1.operator-() cout << coor1.getX() << "," << coor1.getY() << endl; system("pause"); return 0; }
運行結果:
4-2-UnaryOperatorOverloadByFriendFunction
Coordinate.h:
class Coordinate { friend Coordinate &operator-(Coordinate &c); //聲明友元函數運算符重載 public: Coordinate(int x,int y); int getX(); int getY(); private: int m_iX; int m_iY; };
Coordinate.cpp:
#include "Coordinate.h" Coordinate::Coordinate(int x, int y) { m_iX = x; m_iY = y; } int Coordinate::getX() { return m_iX; } int Coordinate::getY() { return m_iY; } // 運算符重載實現 Coordinate &operator-(Coordinate &c) { c.m_iX = -c.m_iX; c.m_iY = -c.m_iY; return c; }
main.cpp,沒有變化。
運行結果也沒有變化。
4-3-PlusPlusOperatorOverload
Coordinate.h
#ifndef COORDINATE_H #define COORDINATE_H #include <iostream> using namespace std; class Coordinate { friend Coordinate &operator-(Coordinate &c); public: Coordinate(int x,int y); Coordinate &operator++();//前置++ Coordinate operator++(int);//後置++,int 標誌這是後置++。不返回引用,返回對象。 int getX(); int getY(); private: int m_iX; int m_iY; }; #endif
Coordinate.cpp
#include "Coordinate.h" Coordinate::Coordinate(int x, int y) { m_iX = x; m_iY = y; } int Coordinate::getX() { return m_iX; } int Coordinate::getY() { return m_iY; } Coordinate &operator-(Coordinate &c) { c.m_iX = -c.m_iX; c.m_iY = -c.m_iY; return c; } Coordinate &Coordinate::operator++() { m_iX++; m_iY++; return *this; } Coordinate Coordinate::operator++(int) { Coordinate old(*this); this->m_iX++; this->m_iY++; return old; }
main.cpp
#include "Coordinate.h" #include <iostream> #include <stdlib.h> using namespace std; int main() { Coordinate coor1(1, 3); cout << coor1.getX() << "," << coor1.getY() << endl; ++coor1; cout << coor1.getX() << "," << coor1.getY() << endl; -coor1; //coor1.operator-() cout << coor1.getX() << "," << coor1.getY() << endl; cout << (coor1++).getX() << ","; cout << (coor1++).getY() << endl; cout << coor1.getX() << "," << coor1.getY() << endl; //上面兩個分號因此coor1++執行了兩次。 //到上一行打印的時候已是x,y都加了2了。 system("pause"); return 0; }
+
號運算符重載方式: 友元函數重載 & 成員函數重載+
成員函數重載class Coordinate { public: Coordinate(int x,int y); Coordinate operator+(const Coordinate &coor); //成員函數 private: int m_iX; int m_iY; } Coordinate operator+(const Coordinate &coor) { Coordinate temp; temp.m_iX = this ->m_iX + coor.m_iX; temp.m_iY = this ->m_iY + coor.m_iY; return temp; } int main() { Coordinate coor1(3,5); Coordinate coor1(4,7); Coordinate coor1(0,0); coor3 = coor1 + coor2; // coor1.operator+(coor2);operator+(coor1,coor2) return 0; }
class Coordinate { friend Coordinate operator+(const Coordinate &c1, const Coordinate &c2); public: Coordinate(int x,int y); private: int m_iX; int m_iY; } // const限制加法不要修改加數自己的值 Coordinate operator+(const Coordinate &c1, const Coordinate &c2) { Coordinate temp; temp.m_iX = c1.m_iX + c2.m_iX; temp.m_iY = c1.m_iY + c2.m_iY; return temp; } int main() { Coordinate coor1(3,5); Coordinate coor1(4,7); Coordinate coor1(0,0); coor3 = coor1 + coor2; // 至關於調用operator+(coor1,coor2) return 0; }
<<
輸出運算符class Coordinate { friend ostream& operator <<(ostream &out,const Coordinate &coor); // 返回值必須是ostream& public: Coordinate(int x,int y); private: int m_iX; int m_iY; } //實現 ostream& operator<<(ostream &out,const Coordinate &coor) { out << coor.m_iX <<","<<coor.m_iY; return out; } //使用 int main() { Coordinate coor(3,5); cout <<coor; //operator<<(cout,coor); return 0; }
理解到cout是一個ostream的對象。
輸出運算符能夠採用成員函數重載?
[]
索引運算符重載class Coordinate { public: Coordinate(int x,int y); int operator[](int index); // 成員函數 private: int m_iX; int m_iY; } int Coordinate::operator [](int index) { if(0==index) {return m_iX;} if(1==index) {return m_iY;} } //使用 int main() { Coordinate coor[3,5]; cout << coor[0]; // coor.operator[](0); cout << coor[1]; // coor.operator[](1); return 0; }
索引運算符能夠採用友元函數重載?
不能採用友元函數重載。友元函數第一個參數能夠是this指針,也能夠是其餘東西: 但是索引運算符,第一個必須是this指針才能指向對象。
4-5-BinaryOperatorOverload
運算符的重載:對於加號運算符,輸出運算符,索引運算符。
Coordinate.h
#ifndef COORDINATE_H #define COORDINATE_H #include <iostream>//包含了ostream using namespace std; class Coordinate { friend Coordinate &operator-(Coordinate &c); friend Coordinate operator+(Coordinate c1,Coordinate c2); friend ostream &operator<<(ostream &output, Coordinate &coor); public: Coordinate(int x,int y); Coordinate &operator++();//前置++ Coordinate operator++(int);//後置++ //Coordinate operator+(Coordinate &c); // 成員函數重載加號 //其實裏面有兩個參數。 int operator [](int index); int getX(); int getY(); private: int m_iX; int m_iY; }; #endif
Coordinate.cpp
#include "Coordinate.h" Coordinate::Coordinate(int x, int y) { m_iX = x; m_iY = y; } int Coordinate::getX() { return m_iX; } int Coordinate::getY() { return m_iY; } Coordinate &operator-(Coordinate &c) { c.m_iX = -c.m_iX; c.m_iY = -c.m_iY; return c; } Coordinate &Coordinate::operator++() { m_iX++; m_iY++; return *this; } Coordinate Coordinate::operator++(int) { Coordinate old(*this); this->m_iX++; this->m_iY++; return old; } //Coordinate Coordinate::operator+(Coordinate &c) //{ // Coordinate temp(0, 0); // temp.m_iX = this->m_iX +c.m_iX; // temp.m_iY = this->m_iY +c.m_iY; // // return temp; //} Coordinate operator+(Coordinate c1, Coordinate c2) { Coordinate temp(0, 0); temp.m_iX = c1.m_iX + c2.m_iX; temp.m_iY = c1.m_iY + c2.m_iY; return temp; } ostream &operator<<(ostream &output, Coordinate &coor) { output << coor.m_iX << "," << coor.m_iY; return output; } int Coordinate::operator [](int index) { if (0 == index) { return m_iX; }if (1 == index) { return m_iY; } }
main.cpp
#include "Coordinate.h" #include <iostream> #include <stdlib.h> using namespace std; int main() { Coordinate coor1(1, 3); Coordinate coor2(2, 4); Coordinate coor3(0, 0); coor3 = coor1 + coor2; //cout << coor3.getX() << "," << coor3.getY() << endl; cout << coor3[0] <<endl; cout << coor3[1] << endl; system("pause"); return 0; }
如索引運算符重載就不可使用友元函數重載,由於索引運算符第一個參數必須傳入this。 輸出運算符
<<
只能用友元函數重載(由於輸出第一個參數爲ostream)。
定義Coordinate類
數據成員:m_iX, m_iY
成員函數:構造函數
重載「--」運算符,重載「+」運算符
#include <iostream> using namespace std; /** * 定義Coordinate類 * 數據成員:m_iX,m_iY * 成員函數:構造函數 * 重載--運算符,重載+運算符 */ class Coordinate { public: Coordinate(int x, int y) { m_iX = x; m_iY = y; } // 前置--運算符重載 Coordinate & operator--() { this ->m_iX--; this ->m_iY--; return *this; } // 後置--運算符重載 Coordinate operator--(int) { Coordinate old = *this; this ->m_iX--; this ->m_iY--; return old; } // +號運算符重載 Coordinate operator+(Coordinate c) { Coordinate temp(0,0); temp.m_iX = this ->m_iX + c.m_iX; temp.m_iY = this ->m_iY + c.m_iY; return temp; } public: int m_iX; int m_iY; }; int main(void) { Coordinate coor1(1, 3); Coordinate coor2(2, 4); Coordinate coor3(0, 0); coor1--; --coor2; coor3 = coor1 + coor2; cout << coor3.m_iX << endl; cout << coor3.m_iY << endl; return 0; }
運行結果:
爲何要使用模板?
// 比較兩個整數 int max(int a,int b) { return (a>b)?a:b; } // 比較兩個浮點數 float max(float a,float b) { return (a>b)?a:b; } // 比較兩個字符串 char max(char a,char b) { return (a>b)?a:b; }
三種不一樣類型,可是運算邏輯徹底一致。
解決方案:
類型做爲參數傳入。計算機來作出這三個函數。
關鍵字:template
typename
class
這裏的class不是類,是來代表數據類型的。
template <class T> // 聲明一種參數類型 T max(T a,T b) //函數模板 { return (a>b)?a:b; } // 不寫明,計算機會自動進行識別 int ival = max(100,99); //模板函數 char cval = max<char>('A','B'); //指定以後,傳入參數必定要是這種數據類型才能夠
函數模板是模子,生產出來的是模板函數。
只有函數模板,計算機不會產生代碼數據; 只有使用時纔會產生真正的代碼
template <typename T> void swap(T& a,T& b) { T tmp = a; a = b; b = tmp; } int x =20,y=30; swap<int>(x,y);
變量做爲模板參數
template <int size> void display() { cout << size <<endl; } display<10>();
多參數函數模板
template <typename T,typename C> void display(T a,C b) { cout << a <<" " <<b <<endl; } //使用 int a = 1024; string str = "helloworld"; display<int,string>(a,str);
typename 和 class能夠混用
template <typename T,class U> T minus(T* a, U b) template <typename T,int size> void display(T a) { for(int i=0;i < size;i++) cout << a << endl; } display<int,5>(15);
函數模板與重載
函數模板能夠作出無數個模板函數來。
模板函數之間造成重載。
不一樣的函數模板作出來的模板函數也能造成重載,好比下面:
template <typename T> void display(T a); template <typename T> void display(T a,T b);//參數個數不一樣 template <typename T,int size> void display(T a); display<int>(10); display<int>(10,20); display<int,5>(30);//三個函數造成重載
函數模板自己不會在內存中產生代碼, 由於沒有模板參數就無從知道要合成怎樣的函數
模板參數能夠是類型, 變量(編譯時其實是常量), 或多個類型和變量的組合
同一個函數模板的不一樣的模板函數之間能夠看做互爲重載
函數名稱相同但模板參數或函數參數不一樣的來自不一樣函數模板的模板函數之間也能夠互爲重載
5-2-FunctionTemplate
main.cpp
#include <iostream> #include <stdlib.h> using namespace std; template <typename T> void display(T a) { cout << a << endl; } template <typename T, class S> void display(T t,S s) { cout << t << endl; cout << s << endl; } template <typename T,int Ksize> //該變量實例化時變爲常量 void display(T a) { for (int i = 0; i < Ksize; i++) { cout << a << endl; } } int main() { display<int>(10); display<double>(10.98); // 模板函數 display<int,double>(5, 8.3); display<int,3>(10); system("pause"); return 0; }
定義一個函數模板,功能是交換兩個數的位置
5-4-swapNum
#include <iostream> using namespace std; #include <stdlib.h> /** * 定義模板函數swapNum * 實現功能:交換兩個數的位置 */ template <typename T> void swapNum(T &a, T &b) { T temp = a; a = b; b = temp; } int main(void) { float x = 10.1; float y = 20.5; // 調用模板函數 swapNum<float>(x, y); cout << "x = " << x << endl; cout << "y = " << y << endl; system("pause"); return 0; }
template <class T> class MyArray { public: void display() {...} private: T *m_pArr; }
只有數據類型不一樣,其餘基本都相同。
類外定義成員函數,須要像下面這樣:
template <class T> //每定義一個類外成員函數,都要在前面寫這行。 // 類名後面寫<T> void MyArray<T>::display() { } //使用 int main() { MyArray<int> arr; arr.display(); return 0; }
類模板
類模板多個參數的使用狀況
template <template T,int KSize> class Container { public: void display(); private: T m_obj; } // 類外定義 template<typename T,int KSize> void Container<T,KSize>::display() { for (int i = 0; i < KSize; ++i) { cout << m_obj << endl; } } int main() { Container<int,10> ct1; ct1.display(); return 0; }
特別提醒:
模板代碼不能分離編譯(類的聲明與定義都要寫在.h文件中)。
template<typename T, int KSize>
5-6-ClassTemplate
MyArray.h:
#ifndef MYARRAY_H #define MYARRAY_H #include <iostream> using namespace std; template <typename T,int Ksize,int KVal>//模板參數列表 class MyArray { public: MyArray(); ~MyArray() { delete[]m_pArr; m_pArr = NULL; }//寫在類內部的函數不須要注意什麼。 void display(); private: T *m_pArr; }; template <typename T, int KSize, int KVal> MyArray<T, KSize, KVal>::MyArray() { m_pArr = new T[KSize]; for (int i = 0; i < KSize; i++) { m_pArr[i] = KVal; } } template <typename T,int KSize,int KVal> void MyArray<T, KSize, KVal>::display() { for (int i = 0; i < KSize; i++) { cout << m_pArr[i] << endl; } } #endif
MyArray.cpp
//什麼都不寫
main.cpp:
#include <stdlib.h> #include <string> #include "MyArray.h" using namespace std; int main() { MyArray<int, 5, 6> arr;//已經造成模板類了 arr.display(); system("pause"); return 0; }
運行結果:
- 定義一個類模板就至關於定義了一系列功能相同類型不一樣的類
定義一個矩形類模板
該模板中含有計算矩形面積和周長的成員函數
數據成員爲矩形的長和寬。
#include <iostream> using namespace std; /** * 定義一個矩形類模板Rect * 成員函數:calcArea()、calePerimeter() * 數據成員:m_length、m_height */ template <typename T> class Rect { public: Rect(T length,T height); T calcArea(); T calePerimeter(); public: T m_length; T m_height; }; /** * 類屬性賦值 */ template <typename T> Rect<T>::Rect(T length,T height) { m_length = length; m_height = height; } /** * 面積方法實現 */ template <typename T> T Rect<T>::calcArea() { return m_length * m_height; } /** * 周長方法實現 */ template <typename T> T Rect<T>::calePerimeter() { return ( m_length + m_height) * 2; } int main(void) { Rect<int> rect(3, 6); cout << rect.calcArea() << endl; cout << rect.calePerimeter() << endl; return 0; }
注意事項:
template <typename T> Rect<T>::Rect(T length,T height)//<T>加在類上而不是方法。
STL: Standard Template Lib
標準模板庫就是系統已經預先寫好了的一些模板的集合,你能夠直接使用(將之實例化)
經常使用部分:
向量(Vecotr)
向量的本質就是對數組的封裝;根據存儲的元素個數自動變長或縮短。
優秀的特色: 隨機讀取能在常數時間內完成
初始化vector對象的方式:
vector<T> v1; // vector保存類型爲T的對象。默認構造函數v1爲空 vector<T> v2(v1); //v2是v1的一個副本 vector<T> v3(n, i); //v3包含n個值爲主的元素 vector<T> v4(n); //v4包含有值初始化元素的n個副本 // 具體的使用 vector<int> ivec1; vector<int> ivec2(ivec1); vector<string> svec1; vector<string> svec2(svec1); vector<int> ivec4(10,-1); //數組中包含10個-1 vector<string> ivec4(10,"hi"); //數組中包含10個hi
上面代碼分別是:
初始化一個空向量
用一個向量初始化另外一個向量
vector經常使用函數:
方法 | 做用 |
---|---|
empty () | 判斷向量是否爲空 |
begin() | 返回向量迭代器首元素 |
end () | 返回向量迭代器末元素的下一個元素 |
clear () | 清空向量 |
front () | 第一個數據 |
back () | 最後一個數據 |
size () | 得到向量中數據大小 |
push_back (elem) | 將數據插入向量尾 |
pop_ back() | 刪除向量尾部數據 |
向量初始化以後必需要有配套的函數才能讓咱們體會到方便,上面這些都是向量的配套函數。
實際使用中的例子以下:
int main() { vector<int> vec; // 傳入參數int vec.push_back(10);//最尾部插入元素10 vec.push_pop();//刪除10 cout << vec.size()<<endl;//此時仍然爲0 return 0; } // 數組的遍歷 for(int k=0;k < vec.size();k++) { cout << vec[k] << endl; }
int main() { vector vec; vec.push_back("hello"); // 尾部插入不少元素 vector<string>::iterator citer = vec.begin(); // 定義一個向量的迭代器 // <>標明向量使用的數據類型。::標識出當前迭代器是屬於向量的迭代器 // 迭代器的變量名citer 數據類型:`vector<string>::iterator citer` // 經過該迭代器指向當前向量的第一個元素。 for (;citer != vec.end();citer++) //停止條件:end指當前向量vec最後一個向量的下一個位置。 //指向下一個元素。 { cout << *citer << endl; // 加*表示指向的元素值。 } }
示意圖以下:
雙鏈表:能夠從頭找到尾,也能夠從尾找到頭。
d 和 e中間插入數據,讓d指向新數據,新數據指向e就能夠了。
特色:數據插入速度快(不像向量,插入一個其餘的所有都得後移)
使用方法上與數組基本相同。
鍵值映射一一對應,經過鍵找值.
map<int,string> m;//經過映射定義一個映射對象 pair<int,string> p1(10,"shanghai");//向映射中放入key&value pair<int,string> p2(20,"beijing"); m.insert(p1); //將pair放入m中 m.insert(p2); cout << m[10] << endl;//經過key訪問值 cout << m[20] << endl;
map<string,string> m;//經過映射定義一個映射對象 pair<string,string> p1("S","shanghai");//向映射中放入key&value pair<string,string> p2("B","beijing"); m.insert(p1);//將pair放入m中 m.insert(p2); cout << m["S"] << endl;//經過key訪問值 cout << m["B"] << endl;
vector使用方法:
6-2-vectorPushBackPopFor
#include <iostream> #include <stdlib.h> #include <vector> #include <list> #include <map> using namespace std; int main() { vector<int> vec; vec.push_back(3);//從尾部去插入 vec.push_back(4); vec.push_back(6); vec.pop_back();//從尾部去除一個 for (int i=0;i<vec.size();i++) { cout << vec[i] << endl; } cout << "end for" << endl; cout << vec.size() << endl; return 0; }
運行結果:
迭代器版本: 6-2-2-IteratorVector
#include <iostream> #include <stdlib.h> #include <vector> #include <list> #include <map> using namespace std; int main() { vector<int> vec; vec.push_back(3);//從尾部去插入 vec.push_back(4); vec.push_back(6); //迭代器 vector<int>::iterator itor = vec.begin(); //cout << *itor << endl; // 打印出來的是第一個元素值 for (;itor != vec.end();itor++) { cout << *itor << endl; } cout << "end iterator" << endl; cout << vec.front() << endl;//第一個元素 cout << vec.back() << endl;//最後一個元素 return 0; }
運行結果:
這裏請注意end獲取到的是最後一個元素的下一個位置
list的遍歷代碼:
6-3-ListOnlyCanUseIterator
#include <iostream> #include <stdlib.h> #include <vector> #include <list> #include <map> using namespace std; int main() { list<int> list1; list1.push_back(4); list1.push_back(7); list1.push_back(10); // for (int i=0;i<list1.size();i++) // { // cout << list1[i] << endl;//錯誤 // } return 0; }
報錯:
Type 'list<int>' does not provide a subscript operator
#include <iostream> #include <stdlib.h> #include <vector> #include <list> #include <map> using namespace std; int main() { list<int> list1; list1.push_back(4); list1.push_back(7); list1.push_back(10); // for (int i=0;i<list1.size();i++) // { // cout << list1[i] << endl;//錯誤 // } list<int>::iterator itor = list1.begin(); for (;itor != list1.end();itor++) { cout << *itor << endl; } return 0; }
6-3-MapIterator
#include <iostream> #include <stdlib.h> #include <vector> #include <list> #include <map> #include <string> using namespace std; int main() { map<int,string> m; pair<int,string> p1(3,"hello"); pair<int,string> p2(6,"world"); //m.push_back(p1); //錯誤,pushback不是map的成員 m.insert(p1); m.insert(p2); cout << m[3] << endl; cout << m[6] << endl; map<int,string>::iterator itor = m.begin(); for (;itor != m.end();itor++) { //cout << *itor << endl;//錯誤,每一個都包含keyvalue cout << itor->first << endl; cout << itor->second << endl; } return 0; }
運行結果:
string類型map
6-3-2-StringMap
#include <iostream> #include <stdlib.h> #include <vector> #include <list> #include <map> #include <string> using namespace std; int main() { map<string,string> m; pair<string,string> p1("H","hello"); pair<string,string> p2("W","world"); //m.push_back(p1);//錯誤 m.insert(p1); m.insert(p2); cout << m["H"] << endl; cout << m["W"] << endl; map<string,string>::iterator itor = m.begin(); for (;itor != m.end();itor++) { //cout << *itor << endl;//錯誤,每一個都包含keyvalue cout << itor->first << endl; //輸出key cout << itor->second << endl;//輸出value } return 0; }
運行結果:
使用vector存儲數字3,6,8,4,並遍歷。
使用map存儲S-Shang Hai B-Bei Jing G-Guang Zhou,並遍歷
6-5-VectorMapIterator
#include <vector> #include <map> #include <string> #include <iostream> using namespace std; int main(void) { // 使用vector存儲數字:三、四、八、4 vector<int> vec; vec.push_back(3); vec.push_back(4); vec.push_back(8); vec.push_back(4); //循環打印數字 vector<int>::iterator itor1 = vec.begin(); for(;itor1 != vec.end();itor1++) { cout << *itor1 <<endl; } // 使用map來存儲字符串鍵值對 map<string, string> m; pair<string, string> p1("S","Shang Hai"); pair<string, string> p2("B","Bei Jing"); pair<string, string> p3("G","Guang Zhou"); m.insert(p1); m.insert(p2); m.insert(p3); // 打印map中數據 map<string, string>::iterator itor2 = m.begin(); for(;itor2 != m.end();itor2++) { cout << itor2->first <<endl; cout << itor2->second <<endl; } return 0; }
運行結果:
注意事項:
cout << itor2->first <<endl; cout << itor2->second <<endl;
itor1和itor2不能重名。