




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第一章 引論第一章 引論21.1 C+程序概貌/helloworld.cpp#include int main() std:cout Hello, world! std:endl; return 0;/* helloworld.c */#include int main() printf(Hello, world!n); return 0;VS第一章 引論31.2 面向?qū)ο蟮幕靖拍瞵F(xiàn)實(shí)中的對象計(jì)算機(jī)中的對象面向過程面向?qū)ο罂陀^存在特定類型的內(nèi)存以過程為中心以對象為中心第一章 引論41.2 面向?qū)ο蟮幕靖拍蠲嫦蜻^程 VS 面向?qū)ο髏ypedef struct int year, month,
2、 day; date;void date_create(date*, int, int, int);void date_add_day(date*, int);class dateprivate: int year, month, day;public: date(int, int, int); void date_add_day(int);VS過程/函數(shù)為中心對象是參數(shù)(從屬地位)對象是主體行為(函數(shù))是從屬第一章 引論51.2 面向?qū)ο蟮幕靖拍?.2.2 面向?qū)ο蟮暮诵母拍蠲嫦驅(qū)ο髷?shù)據(jù)封裝繼承多態(tài)泛型對象的屬性和行為封裝在一個(gè)閉包“類”中新類從已有類擴(kuò)展而出一個(gè)接口,多種實(shí)現(xiàn)以類型無關(guān)的
3、方式編碼第一章 引論61.2 面向?qū)ο蟮幕靖拍?.2.2 面向?qū)ο蟮暮诵母拍顢?shù)據(jù)封裝面向?qū)ο髷?shù)據(jù)封裝繼承多態(tài)泛型未封裝的封裝的所有屬性對外暴露方法不屬于對象對象是方法的參數(shù)a1a2a3m1m2屬性被分類保護(hù)方法從屬于對象對象發(fā)起動作(方法)a2a1m1m2a3VS第一章 引論71.2 面向?qū)ο蟮幕靖拍?.2.2 面向?qū)ο蟮暮诵母拍罾^承面向?qū)ο髷?shù)據(jù)封裝繼承多態(tài)泛型非繼承的繼承的組合/聚集硬邊界在原基礎(chǔ)上擴(kuò)展軟/無邊界VS第一章 引論81.2 面向?qū)ο蟮幕靖拍?.2.2 面向?qū)ο蟮暮诵母拍疃鄳B(tài)面向?qū)ο髷?shù)據(jù)封裝繼承多態(tài)泛型非多態(tài)的多態(tài)的硬編碼ifelse if / switchcase統(tǒng)一接口
4、自動匹配VS虛接口第一章 引論91.2 面向?qū)ο蟮幕靖拍?.2.2 面向?qū)ο蟮暮诵母拍疃鄳B(tài)面向?qū)ο髷?shù)據(jù)封裝繼承多態(tài)泛型實(shí)類型的泛型的硬編碼類型由程序員掌控類型參數(shù)化類型由編譯器自動推導(dǎo)VS模板第一章 引論101.2 面向?qū)ο蟮幕靖拍?.2.3 OOA/D/POOAOODOOP第二章 C+:一個(gè)更好的C第二章 C+:一個(gè)更好的C帶千分位分隔符的二進(jìn)制常量int a = 0b1010101;原始字符串/*是分隔符。符號串n不再是轉(zhuǎn)義字符,而是它們本身const char *s2 = R*(onentwo)*;utf-8編碼的字符串const char *s3 = u8Unicode Chara
5、cters: u4e2du6587;用戶自定義字面常量。這實(shí)際上是個(gè)運(yùn)算符函數(shù)。/功能:將度數(shù)轉(zhuǎn)換為弧度數(shù)。long double operator _d2r(long double degree) return degree * 3.14 / 360.0; sin(30.0_d2r)122.1 基礎(chǔ)類型2.1.1 增強(qiáng)的字面常量第二章 C+:一個(gè)更好的C132.1 基礎(chǔ)類型2.1.2 bool類型bool類型值域條件表達(dá)式邏輯表達(dá)式選擇條件循環(huán)條件與整型的關(guān)系無原生類型,用整型替代0=假,任何非0值=真整型值整型值整型值整型值N/AVSC+C原生false, truebool類型結(jié)果bool
6、類型結(jié)果bool類型結(jié)果bool類型結(jié)果不等價(jià),須轉(zhuǎn)換第二章 C+:一個(gè)更好的C142.1 基礎(chǔ)類型2.1.3 強(qiáng)類型枚舉常量的作用域常量可重名與整型的關(guān)系tag名類型超前聲明全局no常量默認(rèn)為整型不能作為類型名,須與關(guān)鍵字enum一起使用noVS強(qiáng)類型枚舉enum class SIDE LEFT, RIGHT C風(fēng)格枚舉enum SIDE LEFT, RIGHT 被限制,使用時(shí)須加名字限 SIDE:LEFTyes不等價(jià),須轉(zhuǎn)換類型名yes第二章 C+:一個(gè)更好的C指針int a = 1;int *p = &a;內(nèi)存重解釋int a = 1;char *q = (char *)&a;空指針in
7、t *t = nullptr;152.2 地址類型2.2.1 指針類型0 x410 x420 x430 x44apqp = int: 0 x44434241q = char: 0 x41, 0 x42, 0 x43, 0 x44, A B C C第二章 C+:一個(gè)更好的C162.2 地址類型2.2.1 指針類型2.2.1.3 指針使用的問題int a5, *p = a;p6 = 0;指針越界int main() int *p = new int5; return 0;內(nèi)存泄漏void f() int *p = new int5, *q = p; delete p; q0 = 0; delete
8、 q;懸空指針?p?pq第二章 C+:一個(gè)更好的C定義int a = 1;int &r = a;含義對象的別名172.2 地址類型2.2.2 引用類型VS引用int a = 1; int &r = a;指針int a = 1; int *p = &a;1&aap1arr和a是同一個(gè)對象(的不同名字)p和a是兩個(gè)不同的對象第二章 C+:一個(gè)更好的C182.2 基礎(chǔ)類型2.2.2 引用類型定義方式含義用途對象生命期int a = 1; int &r = std:move(a);對象的別名標(biāo)識臨時(shí)對象expiringVS左值引用右值引用int a = 1; int &r = a;對象的別名標(biāo)識常規(guī)對
9、象持久注:C+中的所有具名對象對不能直接綁定到右值引用上第二章 C+:一個(gè)更好的C獨(dú)立引用不常用引用常用于函數(shù)的參數(shù)和返回值類型void f(int& a);void g(int& b);int& h();int& k();192.2 基礎(chǔ)類型2.2.2 引用類型第二章 C+:一個(gè)更好的C202.3 類型自動推導(dǎo)decltype & autodouble f() return 0.0; auto x = 5; /x的類型由初始化值5的類型確定。因?yàn)樽置娉A?的編譯器默認(rèn)類型是int,所以x的類型就是intauto *px = &x; /px的類型是int *static auto y = 0.
10、0; /y的類型是doubleauto z = f(); /z的類型是f()的返回值類型,即doubleauto int r; /error,auto不再是存儲分類符decltypeautodouble f() return 0.0; /函數(shù)定義int i = 0;decltype(i) j; /j的類型從對象i的類型推到而來,即是intdecltype(i) ri = i; /括起對象i的圓括號指明ri的類型引用,本例是const int &double l = 1.0;decltype(f() k; /k的類型是f()的返回值類型,即doubledecltype(f() rl = l; /
11、rl的類型是const double &char *p;decltype(p) q = nullptr; /q的類型是char *,并被初始化第二章 C+:一個(gè)更好的C動態(tài)內(nèi)存分配new / new delete / delete 類型轉(zhuǎn)換static_castconst_castdynamic_castreinterpret_cast獲取類型信息typeid #include 212.4 運(yùn)算符和表達(dá)式2.4.1 C+特有的運(yùn)算符第二章 C+:一個(gè)更好的Clambda表達(dá)式一種輕量級匿名函數(shù)屬于閉包(closure)類型語法捕獲列表(參數(shù)列表)-返回值類型 復(fù)合語句示例auto square
12、 = (int x)-int return x * x; ;std:cout int return a + b; 返回類型自動推導(dǎo)auto f(int i) if (i = 0) return 1; /根據(jù)整形常量1的類型,編譯器推導(dǎo)出f的返回類型是int else if (i = 0) return 0; /OK else return -1.0; /error,每條路徑返回的類型不一樣322.7 函數(shù)2.7.3 函數(shù)的返回值第二章 C+:一個(gè)更好的C結(jié)構(gòu)化綁定struct X int a; double b; ;X f() return 1, 2.3; auto a, b = f(); /
13、對象a/b不能提前聲明/定義函數(shù)返回lambdaauto f() return (int a)-int return a * a; ; auto square = f(); /square是一個(gè)lambdasquare(3); /9f()(3); /9332.7 函數(shù)2.7.3 函數(shù)的返回值第二章 C+:一個(gè)更好的C當(dāng)兩個(gè)或多個(gè)在相同范圍內(nèi)的聲明用的是同一個(gè)名字時(shí),這個(gè)名字就被稱為“重載(overloading)”double abs(double num) long abs(long num) int abs(int num) 區(qū)分不同重載版本的唯一依據(jù)是函數(shù)的參數(shù)列表,即重載函數(shù)必須在參數(shù)
14、個(gè)數(shù)和/或參數(shù)類型不同。僅返回值類型不同不能被視為是函數(shù)重載。342.7 函數(shù)2.7.4 函數(shù)重載第二章 C+:一個(gè)更好的C作為另一個(gè)函數(shù)的參數(shù)的函數(shù)稱為回調(diào)函數(shù)(callback)。如果回調(diào)函數(shù)返回bool值,則它往往又被稱為謂詞(predicate)。示例void f(void (*callback1)(); /callback1是一個(gè)指針,其類型是函數(shù)指針void g(void callback2(); /callback2是一個(gè)函數(shù),其類型是函數(shù)。/以上兩個(gè)函數(shù)的參數(shù)雖然類型不同,但卻是等效的。352.7 函數(shù)2.7.5 回調(diào)函數(shù)第二章 C+:一個(gè)更好的Ctypedef void (*
15、FUN_PTR)(); /FUN_PTR是指向函數(shù)的指針類型的名字,不是對象名typedef void FUN(); /FUN是函數(shù)類型的名字,不是對象名或者using FUN_PTR = void (*)();using FUN = void ();void g(FUN_PTR p) (*p)(); /還可以寫成:p();/void g(FUN p) p(); /FUN類型參數(shù)與FUN_PTR類型參數(shù)等效FUN_PTR h() return f; /FUN h() return f; /error362.8 類型聲明簡化typedef和using第二章 C+:一個(gè)更好的Ctypedef vo
16、id (*FUN_PTR)(); /FUN_PTR是指向函數(shù)的指針類型的名字,不是對象名typedef void FUN(); /FUN是函數(shù)類型的名字,不是對象名void g(FUN_PTR p) (*p)(); /還可以寫成:p();/void g(FUN p) p(); /FUN類型參數(shù)與FUN_PTR類型參數(shù)等效FUN_PTR h() return f; /FUN h() return f; /error372.8 類型聲明簡化using第二章 C+:一個(gè)更好的Cnamespace myspacestruct X ; /類型定義using XPTR = X*; /類型別名void f(
17、) ; /函數(shù)定義int counter = 0; /對象定義和初始化myspace:X x;或者using namespace myspace;X x;382.9 名字空間第三章 類:面向?qū)ο蟮幕谌?類:面向?qū)ο蟮幕痷sing value_t = int; /類型別名struct _node /節(jié)點(diǎn)類型定義 value_t data; /數(shù)據(jù)域 _node * next; /指針域;using node_ptr = _node *; /類型別名struct linked_list node_ptr head, tail; /頭尾指針 size_t _size; /節(jié)點(diǎn)數(shù)目;403.1
18、 案例-鏈表的實(shí)現(xiàn)3.1.1 案例及其實(shí)現(xiàn)鏈表的設(shè)計(jì)12345headtail鏈表圖3-1 鏈表結(jié)構(gòu)示意圖第三章 類:面向?qū)ο蟮幕?鏈表的操作:原型聲明/初始化鏈表extern void init(linked_list& l);/在鏈表尾部添加數(shù)據(jù)extern void push_back(linked_list& l, value_t d);/清空鏈表extern void clear(linked_list& l);413.1 案例-鏈表的實(shí)現(xiàn)3.1.1 案例及其實(shí)現(xiàn)鏈表的操作(原型)第三章 類:面向?qū)ο蟮幕疢akefilesources = *.cppcflags = -std=c
19、+17 -Walltarget = llistsanitizer = -fsanitize=addressall: $(CXX) $(sources) $(cflags) $(sanitizer) -o $(target)命令行$ make423.1 案例-鏈表的實(shí)現(xiàn)3.1.1 案例及其實(shí)現(xiàn)項(xiàng)目建造第三章 類:面向?qū)ο蟮幕瘜ο笫且粋€(gè)主動的實(shí)體,它包含有屬性和行為。linked_list只是封裝了屬性。屬于對象的行為不得不用一些沒有任何隸屬關(guān)系的全局函數(shù)來實(shí)現(xiàn)。從邏輯、安全等各種角度出發(fā),鏈表的內(nèi)部細(xì)節(jié)應(yīng)該是對客戶程序員隱蔽的,他們不需要也沒有必要知道鏈表的實(shí)現(xiàn)細(xì)節(jié)。然而在實(shí)現(xiàn)中,鏈表的屬性是
20、沒有任何保護(hù)的,直接暴露在程序空間中。433.1 案例-鏈表的實(shí)現(xiàn)3.1.2 案例問題分析第三章 類:面向?qū)ο蟮幕痗lass linked_listprivate: node_ptr head, tail; size_t _size;public: void init(); void push_back(value_t d); void clear(); size_t size();443.2 類3.2.1 定義類類型和對象數(shù)據(jù)成員成員函數(shù)第三章 類:面向?qū)ο蟮幕陬愅舛xvoid linked_list:init() head = tail = nullptr; _size = 0;在類
21、內(nèi)定義class linked_listpublic: void init() head = tail = nullptr; _size = 0; ;453.2 類3.2.1 定義類類型和對象成員函數(shù)的定義名字限定第三章 類:面向?qū)ο蟮幕x類對象linked_list l;訪問對象的成員l.init();463.2 類3.2.1 定義類類型和對象定義類對象headtail圖3-3對象的內(nèi)存布局_size第三章 類:面向?qū)ο蟮幕疌+編譯器會為每一個(gè)類對象的所有非靜態(tài)(3.2.3節(jié))成員函數(shù)設(shè)置一個(gè)this指針,并且這個(gè)指針指向了類對象本身。例如有:linked_list l; 那么l對象的
22、this指針可以形式化地看作是這樣定義的:linked_list * const this = &l;有了this指針,成員init()的實(shí)現(xiàn)可以認(rèn)為被編譯器改成如下形式 void linked_list:init() this-head = this-tail = nullptr; this-_size = 0; 因此,即使所有類對象都共享了init()成員的代碼,但因this指針的存在,init()也非常清楚自己是由哪個(gè)對象(this指針指向的對象)發(fā)起的。473.2 類3.2.1 定義類類型和對象this指針第三章 類:面向?qū)ο蟮幕痗lass linked_listprivate: n
23、ode_ptr head, tail; size_t _size;public: void init(); void push_back(value_t d); void clear(); size_t size();483.2 類3.2.2 訪問控制私有段,段內(nèi)成員類外不可見,即類外不可直接訪問。共有段,段內(nèi)成員類外可見訪問控制保護(hù)的是類,而非單個(gè)類對象。因此,在類的成員函數(shù)中,可以直接訪問該類對象的所有成員。第三章 類:面向?qū)ο蟮幕痷sing callback = void (value_t&); /定義函數(shù)類型void linked_list:traverse(callback af)
24、 for (node_ptr p = head; p != nullptr; p = p-next) af(p-data);l.traverse(value_t& v) std:cout v ; );493.2 類3.2.2 訪問控制封裝遍歷操作第三章 類:面向?qū)ο蟮幕痗lass fooprivate: int a; static int b;public: static int c; void set(int x) a = x; static void f() std:cout b c std:endl; static void g(const foo& o) std:cout o.a s
25、td:endl; ;int foo:b = 0;int foo:c = 1;503.2 類3.2.3 類的靜態(tài)成員實(shí)例成員。對象存在該類成員才存在。靜態(tài)數(shù)據(jù)成員。該類成員的存在不依賴于類對象。靜態(tài)成員屬于類而非類對象。靜態(tài)成員函數(shù)。主要用于訪問其他靜態(tài)成員。靜態(tài)成員函數(shù)沒有this指針。靜態(tài)成員函數(shù)要訪問實(shí)例成員,應(yīng)該向它傳遞一個(gè)對象。靜態(tài)數(shù)據(jù)函數(shù)的內(nèi)存分配必須在類外顯式完成,并被初始化。第三章 類:面向?qū)ο蟮幕痵truct和union都是特殊的類。在缺省段描述符的情況下,struct的成員都是公有的。相較而言,class的則是私有的。union的成員只能是公有的。最好以C的方式使用。513
26、.2 類3.2.4 struct和union第三章 類:面向?qū)ο蟮幕惖某蓡T可以是其它類的實(shí)例。這使得前者間接獲得后者的功能。這是類與類之間合作的一種模式。523.2 類3.2.5 組合和聚集聚集部件可以單獨(dú)存在組合部件不能單獨(dú)存在第三章 類:面向?qū)ο蟮幕悓ο笤诙x后應(yīng)該被初始化。以前的做法是調(diào)用初始化方法。但這存在缺陷。更好的初始化方法是自動化 - 構(gòu)造函數(shù)(constructor)類對象在失效后應(yīng)該清理它占據(jù)的資源。以前的做法是調(diào)用清理方法。但這也存在缺陷。更好的清理方法仍然是自動化 析構(gòu)函數(shù)(destructor)533.3 對象的構(gòu)造、初始化和析構(gòu)第三章 類:面向?qū)ο蟮幕痗la
27、ss linked_listprivate:node_ptr head = nullptr;node_ptr tail = nullptr;size_t _size = 0;543.3 對象的構(gòu)造、初始化和析構(gòu)初始化Inline模式第三章 類:面向?qū)ο蟮幕痗lass T /T是類名public:T(參數(shù)列表) 語句 /這是一個(gè)構(gòu)造函數(shù);實(shí)際上,構(gòu)造函數(shù)沒有名字!因此不能被顯式調(diào)用。引起構(gòu)造函數(shù)“調(diào)用”的語法稱為“函數(shù)標(biāo)記法(functional notation)”,其形式非常類似于函數(shù)調(diào)用。構(gòu)造函數(shù)沒有也不能有返回類型!553.3 對象的構(gòu)造、初始化和析構(gòu)3.3.1 構(gòu)造函數(shù)第三章 類:面
28、向?qū)ο蟮幕J(rèn)的構(gòu)造函數(shù):沒有參數(shù)linked_list:linked_list() linked_list l; /這里,默認(rèn)構(gòu)造函數(shù)被編譯器自動調(diào)用顯式聲明的構(gòu)造函數(shù)class linked_list public: explicit linked_list() . ;563.3 對象的構(gòu)造、初始化和析構(gòu)3.3.1 構(gòu)造函數(shù)默認(rèn)和顯式聲明的構(gòu)造函數(shù)第三章 類:面向?qū)ο蟮幕瘶?gòu)造函數(shù)的參數(shù):可以是默認(rèn)的linked_list:linked_list(size_t len, value_t* a = nullptr) value_t d = ;linked_list l(5, d);link
29、ed_list k(0); 573.3 對象的構(gòu)造、初始化和析構(gòu)3.3.1 構(gòu)造函數(shù)構(gòu)造函數(shù)的參數(shù)第三章 類:面向?qū)ο蟮幕瘶?gòu)造函數(shù)的初始化列表:出現(xiàn)在函數(shù)頭部linked_list(size_t len, value_t* a) : head(nullptr), tail(nullptr), _size(0) 構(gòu)造函數(shù)的初始化列表先于其“函數(shù)體”執(zhí)行。類的常量和引用成員只能在初始化列表中被初始化。583.3 對象的構(gòu)造、初始化和析構(gòu)3.3.1 構(gòu)造函數(shù)構(gòu)造函數(shù)的初始化列表第三章 類:面向?qū)ο蟮幕痗lass Aprivate: int i;public: A(int x) : i(x) ;c
30、lass Bprivate: A a;public: B(int x) : a(x) ;593.3 對象的構(gòu)造、初始化和析構(gòu)3.3.1 構(gòu)造函數(shù)嵌入對象的初始化第三章 類:面向?qū)ο蟮幕痩inked_list();linked_list(size_t len, value_t* a);linked_list(const std:initializer_list& l);603.3 對象的構(gòu)造、初始化和析構(gòu)3.3.2 構(gòu)造函數(shù)重載初始化列表第三章 類:面向?qū)ο蟮幕痩inked_list() : head(nullptr), tail(nullptr), _size(0) linked_list
31、(size_t len, value_t* a) : linked_list() linked_list(std:initializer_list& l) : linked_list() 613.3 對象的構(gòu)造、初始化和析構(gòu)3.3.2 構(gòu)造函數(shù)重載構(gòu)造函數(shù)委托第三章 類:面向?qū)ο蟮幕?23.3 對象的構(gòu)造、初始化和析構(gòu)3.3.3 統(tǒng)一初始化int a = 1; /等價(jià)于 int a = 1int b2; /等價(jià)于 int b = 2int *p = new int41, 2, 3, 4; /數(shù)組p的每個(gè)元素都被初始化X n; /n未初始化n = 7, 8 ; /賦值class Y publi
32、c: int c; double d; Y(int x, double y) : c(x), d(y) m5, 6.0; /call constructor, m.c = 5,m.d = 6.0VS常規(guī)初始化統(tǒng)一初始化int a = 0; /復(fù)制初始化const char *p(string); /直接初始化linked_list l(5); /直接初始化,使用了默認(rèn)參數(shù)linked_list k = 1, 2, 3, 4; /復(fù)制初始化第三章 類:面向?qū)ο蟮幕痗lass T /T是類名public:T() 語句 /這是一個(gè)析構(gòu)函數(shù);析構(gòu)函數(shù)在對象失效時(shí)被編譯器自動調(diào)用。析構(gòu)函數(shù)能被顯式調(diào)用
33、,但調(diào)用后對象將失效。析構(gòu)函數(shù)不能有參數(shù)!析構(gòu)函數(shù)沒有也不能有返回類型!633.3 對象的構(gòu)造、初始化和析構(gòu)3.3.4 析構(gòu)函數(shù)第三章 類:面向?qū)ο蟮幕[式默認(rèn)的特殊成員class X ;因?yàn)闆]有顯式定義,所以類X的構(gòu)造函數(shù)和析構(gòu)函數(shù)都是隱式默認(rèn)(implicit default)的。隱式默認(rèn)的成員由編譯器合成。顯式默認(rèn)的特殊成員struct XX() noexcept = default; /顯式默認(rèn)構(gòu)造函數(shù)必須沒有參數(shù) X() noexcept = default;643.3 對象的構(gòu)造、初始化和析構(gòu)3.3.5 默認(rèn)和被刪除的成員函數(shù)第三章 類:面向?qū)ο蟮幕痵truct X X() =
34、 delete; X(int) noexcept ;X a; /error,默認(rèn)構(gòu)造函數(shù)被刪除X b1; /OK653.3 對象的構(gòu)造、初始化和析構(gòu)3.3.5 默認(rèn)和被刪除的成員函數(shù)第三章 類:面向?qū)ο蟮幕?63.5 面向?qū)ο蠓椒ǖ膽?yīng)用3.5.1 OOA幾個(gè)必須回答的問題Why我們?yōu)槭裁匆_發(fā)這樣的應(yīng)用系統(tǒng)?Who誰會使用這個(gè)應(yīng)用系統(tǒng)?How用戶會用什么樣的方式使用這個(gè)系統(tǒng)?When用戶何時(shí)會使用這個(gè)系統(tǒng)?Where用戶在什么場景下會使用這個(gè)系統(tǒng)?What基于上述問題,我們要開發(fā)出什么樣的系統(tǒng)?第三章 類:面向?qū)ο蟮幕?73.5 面向?qū)ο蠓椒ǖ膽?yīng)用3.5.1 OOA案例的用例圖第三章 類:
35、面向?qū)ο蟮幕嫦驅(qū)ο笤O(shè)計(jì)的主要過程(但不是全部)包括:系統(tǒng)體系結(jié)構(gòu)設(shè)計(jì)。類/對象設(shè)計(jì)。用戶界面設(shè)計(jì)。683.5 面向?qū)ο蠓椒ǖ膽?yīng)用3.5.2 面向?qū)ο笤O(shè)計(jì)第三章 類:面向?qū)ο蟮幕繕?biāo)系統(tǒng)是一個(gè)獨(dú)立的應(yīng)用系統(tǒng)。因此,系統(tǒng)的體系結(jié)構(gòu)應(yīng)該是集中式的,即有一個(gè)總控模塊調(diào)度其他功能模塊。接下來要進(jìn)行的是系統(tǒng)的模塊分解。根據(jù)前面的分析,可以很容易地確定,系統(tǒng)的功能模塊由四個(gè)部分組成:693.5 面向?qū)ο蠓椒ǖ膽?yīng)用3.5.2 面向?qū)ο笤O(shè)計(jì)體系結(jié)構(gòu)設(shè)計(jì)總控輸入計(jì)算輸出第三章 類:面向?qū)ο蟮幕粋€(gè)簡單易行的方法就是列出使用場景的流程,然后在流程中找出活動對象。僅保留那些與應(yīng)用直接相關(guān)的對象。標(biāo)識出這些對象
36、之間的關(guān)系。在案例的使用場景中,活動對象有兩個(gè):用戶和計(jì)算器。前者并不需要標(biāo)識。因此,本系統(tǒng)中活動的對象只有一個(gè),那就是計(jì)算器。這里,我們將其標(biāo)識為:calculator。703.5 面向?qū)ο蠓椒ǖ膽?yīng)用3.5.2 面向?qū)ο笤O(shè)計(jì)標(biāo)識系統(tǒng)中的類/對象第三章 類:面向?qū)ο蟮幕痗lass expression public lhs: integer; public rhs: integer; public optr: char; public result: integer;class calculator private expr: expression; private input() : vo
37、id; private calculate() : void; private display() : void; public doCalc() : void;713.5 面向?qū)ο蠓椒ǖ膽?yīng)用3.5.2 面向?qū)ο笤O(shè)計(jì)類的接口設(shè)計(jì)第三章 類:面向?qū)ο蟮幕?23.5 面向?qū)ο蠓椒ǖ膽?yīng)用3.5.2 面向?qū)ο笤O(shè)計(jì)其他工作用戶界面設(shè)計(jì)人機(jī)界面設(shè)計(jì)原則編碼實(shí)現(xiàn)添加實(shí)現(xiàn)細(xì)節(jié)代碼測試交付和運(yùn)維用戶的反饋系統(tǒng)升級和維護(hù)第四章 類的高級特性第四章 類的高級特性744.1 案例-鏈表類的復(fù)制問題4.1.1 案例及其實(shí)現(xiàn)復(fù)雜類型的復(fù)制操作a:1b:2.3a:?b:?o1o2復(fù)制復(fù)制的兩種方式:X o2o1;o2 =
38、 o1;a:1b:2.3可以視為是內(nèi)存復(fù)制第四章 類的高級特性linked_list:linked_list() : head(nullptr), tail(nullptr), _size(0) std:cout in default constructor std:endl; linked_list:linked_list(const std:initializer_list& l) : head(nullptr), tail(nullptr), _size(0) for (auto e : l) push_back(e); std:cout in list constructor std:
39、endl;linked_list:linked_list() clear(); std:cout in destructor std:endl;754.1 案例-鏈表類的復(fù)制問題4.1.1 案例及其實(shí)現(xiàn)鏈表的構(gòu)造函數(shù)和析構(gòu)函數(shù)第四章 類的高級特性void linked_list:peer() std:cout | head tail _size std:endl; int main() auto af = (value_t& v) std:cout v ; ; linked_list l11, 2, 3, 4, 5; /定義對象并初始化 std:cout l1: ; l1.traverse(a
40、f); l1.peer(); linked_list l2l1; /初始化復(fù)制 std:cout l2: ; l2.traverse(af); l2.peer(); return 0;764.1 案例-鏈表類的復(fù)制問題4.1.1 案例及其實(shí)現(xiàn)鏈表的復(fù)制初始化時(shí)有兩個(gè)對象定義,因此應(yīng)該有兩條構(gòu)造和析構(gòu)信息in list constructorl1: 1 2 3 4 5 | 0 x602000000010 0 x602000000090 5l2: 1 2 3 4 5 | 0 x602000000010 0 x602000000090 5in destructor=5430=ERROR: Addre
41、ssSanitizer: attempting double-free on 0 x602000000010 in thread T0: #0 0 x7fe3dff1e0f8 in operator delete(void*, unsigned long) ././././libsanitizer/asan/asan_new_delete.cc:151 #1 0 x40100f in linked_list:clear() /此后是詳細(xì)的診斷信息,故略去第四章 類的高級特性void linked_list:peer() std:cout | head tail _size std:endl;
42、int main() auto af = (value_t& v) std:cout v ; ; linked_list l11, 2, 3, 4, 5; /定義對象并初始化 std:cout l1: ; l1.traverse(af); l1.peer(); linked_list l2; l2 = l1; /賦值 std:cout next) push_back(p-data);第四章 類的高級特性884.2 復(fù)制控制4.2.3 淺復(fù)制和深復(fù)制優(yōu)缺點(diǎn)對比代價(jià)較高。需要考慮復(fù)制的深度??赡懿恍枰Y源共享安全風(fēng)險(xiǎn)較低VS淺復(fù)制深復(fù)制代價(jià)較小可能導(dǎo)致資源共享安全風(fēng)險(xiǎn)較高第四章 類的高級特性894
43、.2 復(fù)制控制4.2.4 轉(zhuǎn)移對象和轉(zhuǎn)移語義可能的復(fù)制路徑class object ;object f() object t; return t;/返回局部對象的值auto a = f();復(fù)制復(fù)制t資源r匿名臨時(shí)對象r的副本a資源sr的副本這個(gè)過程有問題嗎?第四章 類的高級特性904.2 復(fù)制控制4.2.4 轉(zhuǎn)移對象和轉(zhuǎn)移語義效率問題復(fù)制復(fù)制t資源r匿名臨時(shí)對象r的副本a資源sr的副本這個(gè)對象在復(fù)制后失效,資源被釋放這個(gè)資源在復(fù)制時(shí)釋放這個(gè)資源是復(fù)制而來這正是(早期的)C+被詬病的問題之一。有無好辦法解決這類效率問題呢?第四章 類的高級特性914.2 復(fù)制控制4.2.4 轉(zhuǎn)移對象和轉(zhuǎn)移語義解
44、決思路復(fù)制復(fù)制t資源r匿名臨時(shí)對象r的副本a資源sr的副本直接“轉(zhuǎn)移”給a資源s轉(zhuǎn)移給轉(zhuǎn)義對象去釋放這類即將失效(expiring)的對象稱為“轉(zhuǎn)移對象”,用右值引用標(biāo)記第四章 類的高級特性924.2 復(fù)制控制4.2.4 轉(zhuǎn)移對象和轉(zhuǎn)移語義編碼實(shí)現(xiàn)linked_list& operator=(linked_list& l) std:swap(head, l.head); std:swap(tail, l.tail); std:swap(_size, l._size); return *this;轉(zhuǎn)移復(fù)制構(gòu)造函數(shù)轉(zhuǎn)移賦值運(yùn)算符函數(shù)linked_list(linked_list& l) : hea
45、d(l.head), tail(l.tail), _size(l._size) l.head = l.tail = nullptr; l._size = 0;第四章 類的高級特性私有構(gòu)造函數(shù),但僅聲明,無實(shí)現(xiàn)linked_list(const linked_list&);禁止合成linked_list(const linked_list&) = delete; linked_list& operator=(const linked_list& l) = delete;934.2 復(fù)制控制4.2.5 禁止復(fù)制第四章 類的高級特性概念類型名 類名:*指針;類型名 (類名:*指針)(參數(shù)列表);初始
46、化指針 = &類名:成員名;使用對象.*指針;對象-*指針;944.3 指向類成員的指針4.2.5 禁止復(fù)制第四章 類的高級特性初衷僅僅出于效率的考慮。原則一個(gè)類的友元可以直接訪問它的所有成員。954.4 友元class 類名A /other members; friend 函數(shù)原型聲明; /全局友元函數(shù)聲明 friend 類名B:成員函數(shù)原型聲明; /成員函數(shù)友元聲明 friend class 類名C; /友元類聲明 /友元聲明放在哪個(gè)段無關(guān)緊要;友元特性:非傳遞性非對稱性第四章 類的高級特性class Xprivate: const int a; /如果沒有初始化,那么只能在構(gòu)造函數(shù)的初始
47、化列表里進(jìn)行 const int c = 1; /OK int b;public: X(int i, int j) : a(i), b(j) const int get_c() const return c; ;964.5 常量和mutable成員4.5.1 常量成員第四章 類的高級特性class Ypublic: Y() : x(0), y(0) int x; mutable int y;const Y o;o.x = 1; /erroro.y = 2; /OK974.5 常量和mutable成員4.5.2 mutable成員第四章 類的高級特性class encirclepublic: i
48、nt i;class nested public: void f();void g() encircle:nested n; /OK984.6 類中的類型名4.6.1 類中的類類型嵌套類包圍類嵌套類定義在包圍類的public段中void encircle:nested:f() i = 0; /error,包圍類的成員對嵌套類是不可見的 encircle:i = 0; /error,i不是encircle類的靜態(tài)成員第四章 類的高級特性class encirclepublic:enum STATUS WRONG, RIGHT ;encircle:STATUS s = encircle:RIGHT
49、; /OKs = WRONG; /error994.6 類中的類型名4.6.2 類中的枚舉類型第四章 類的高級特性class encirclepublic: typedef int* pointer; using pointer2 = int *; /OK,與typedef等效;encircle:pointer p; /OKpointer2 q; /errortypename encircle:pointer2 t;1004.6 類中的類型名4.6.3 類中的類型別名以及typename關(guān)鍵字明確告知編譯器:pointer2是類encircle中的類型而非其普通成員第五章 運(yùn)算符重載第五章 運(yùn)
50、算符重載1025.1 案例-complex類的運(yùn)算5.1.1 案例及其實(shí)現(xiàn)及問題分析class complexprivate: double real, imag;public: complex(double r = 0, double i = 0) : real(r), imag(i) ;complex c11.2, 2.3, c23.4, 4.5, c3;c3 = c1 + c2;編譯器對這行報(bào)出錯(cuò)誤。主要原因是:c1c3都是程序員自定義類的對象,編譯器并不知道+運(yùn)算符作用在這些類對象上有什么特定含義,也不知道該如何操作。解決問題的方法就是運(yùn)算符函數(shù)重載。第五章 運(yùn)算符重載在C+中,很多的
51、運(yùn)算符被當(dāng)視為函數(shù),稱為運(yùn)算符函數(shù)(operator function)返回值類型 operator (參數(shù)列表);1035.2 運(yùn)算符函數(shù)重載第五章 運(yùn)算符重載為類重載運(yùn)算符函數(shù),有幾個(gè)因素需要考量:1045.2 運(yùn)算符函數(shù)重載5.2.1 考量因素語義運(yùn)算符的原始語義重載形式重載為成員重載為友元特征參數(shù)個(gè)數(shù)/類型返回值類型級聯(lián)運(yùn)算能否級聯(lián)(cascading)第五章 運(yùn)算符重載int a = 1, b = 2, c;c = a + b;運(yùn)算時(shí),操作數(shù)a和b都不會被改變。運(yùn)算后,加法要產(chǎn)生一個(gè)新的值結(jié)果,而不是保存在a和b當(dāng)中的任何一中。這個(gè)結(jié)果是以右值對象的形式標(biāo)識的,它不能作為左值使用???/p>
52、以級聯(lián)。1055.2 運(yùn)算符函數(shù)重載5.2.1 考量因素示例:加法運(yùn)算的語義第五章 運(yùn)算符重載根據(jù)語義,為complex類重載的+函數(shù)最好是它的友元。class complex friend complex operator+(const complex& a, const complex& b);complex operator+(const complex& a, const complex& b) return complexa.real + b.real, a.imag + b.imag;c3 = c1 + c2;1065.2 運(yùn)算符函數(shù)重載5.2.2 一般性規(guī)則重載規(guī)則常量參數(shù)保證操
53、作數(shù)不會被改變返回值結(jié)果。它不能作為左值作為友元,可直接訪問類成員這條語句被編譯器解釋為:c3 = :operator+(c1, c2)思考:+可不可以重載為complex類的成員呢?如果可以,要考慮哪些問題?如何處理級聯(lián)?第五章 運(yùn)算符重載1075.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則【規(guī)則一】大多數(shù)系統(tǒng)預(yù)定義的運(yùn)算符可以通過重載重定義它們作用在用戶定義類型上的新含義。只有以下少數(shù)的C+運(yùn)算符不能重載::(作用域解析運(yùn)算符)?:(條件運(yùn)算符).(成員選擇運(yùn)算符).*(成員選擇運(yùn)算符)第五章 運(yùn)算符重載1085.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則【規(guī)則二】重載運(yùn)算符時(shí):不能改變它們的優(yōu)先
54、級不能改變它們的結(jié)合性不能改變這些運(yùn)算符所需操作數(shù)的數(shù)目第五章 運(yùn)算符重載【規(guī)則三】重載的運(yùn)算符必須和用戶自定義的類對象一起使用,其參數(shù)至少應(yīng)有一個(gè)是類對象(或類對象的引用)。【規(guī)則四】用于類對象的運(yùn)算符一般必須重載。1095.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則第五章 運(yùn)算符重載【規(guī)則五】保持原始語義?!疽?guī)則六】重載的運(yùn)算符函數(shù)不能是類的靜態(tài)成員。1105.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則第五章 運(yùn)算符重載【建議一】 下表給出了該函數(shù)應(yīng)該是作為類的成員還是友元的建議。1115.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則參數(shù)和返回類型的設(shè)定建議運(yùn)算符重載為成員還是友元= () - type
55、-casting必須是成員單目運(yùn)算符建議為成員復(fù)合賦值運(yùn)算符建議為成員其它雙目運(yùn)算符建議為友元第五章 運(yùn)算符重載【建議二】 對于重載的單目運(yùn)算符函數(shù):作為成員重載時(shí),函數(shù)沒有參數(shù),運(yùn)算作用在lhs上;函數(shù)返回lhs的左值引用。作為友元重載是,函數(shù)有一個(gè)參數(shù)(并且是左值引用),運(yùn)算作用在參數(shù)對象上;函數(shù)返回參數(shù)對象的左值引用。當(dāng)然,這是不推薦的重載方式。這條規(guī)則關(guān)于參數(shù)個(gè)數(shù)有例外,就是當(dāng)是后綴+/-時(shí)。1125.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則參數(shù)和返回類型的設(shè)定建議第五章 運(yùn)算符重載【建議三】 對于作為成員重載的雙目運(yùn)算符(必須有充分的理由這么做):函數(shù)有一個(gè)參數(shù),這個(gè)參數(shù)就是rhs,并
56、且是常量。產(chǎn)生的結(jié)果保存到lhs中。函數(shù)的返回值是lhs的左值引用。1135.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則參數(shù)和返回類型的設(shè)定建議第五章 運(yùn)算符重載【建議四】 對于作為友元重載的雙目運(yùn)算符:有兩個(gè)參數(shù)(即左右操作數(shù)),并且都是常量,且這兩個(gè)參數(shù)中至少有一個(gè)是將該運(yùn)算符函數(shù)作為友元對待的類的對象。 如果參數(shù)不是指針/引用,那么會引起類的復(fù)制構(gòu)造函數(shù)的調(diào)用。因此,最好為類顯式定義一個(gè)復(fù)制構(gòu)造函數(shù)。2. 函數(shù)產(chǎn)生一個(gè)新值,即返回值是一個(gè)值對象(非引用非指針)。 這同樣會引起復(fù)制構(gòu)造函數(shù)的調(diào)用。1145.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則參數(shù)和返回類型的設(shè)定建議第五章 運(yùn)算符重載【建議五
57、】 對于關(guān)系和邏輯運(yùn)算符,它們應(yīng)該產(chǎn)生一個(gè)bool類型的結(jié)果。 如果使用的編譯器不支持bool類型,那么應(yīng)該返回一個(gè)替代的整型值:1表示真,0表示假?!窘ㄗh六】 如果作為成員重載的運(yùn)算只是讀取對象的屬性而不會改變它們,那么建議將該函數(shù)設(shè)為常成員。1155.2 運(yùn)算符函數(shù)重載5.2.2 重載規(guī)則參數(shù)和返回類型的設(shè)定建議第五章 運(yùn)算符重載常規(guī)運(yùn)算符賦值(含復(fù)合賦值)、算數(shù)、關(guān)系要點(diǎn)保持語義不變?nèi)绻淖冊颊Z義,那么應(yīng)當(dāng)賦予運(yùn)算符顯而易見的、容易理解的語義根據(jù)需要重載為友元或是成員1165.3 常規(guī)運(yùn)算符的重載第五章 運(yùn)算符重載如何區(qū)分前綴和后綴?以+為例class complexpublic:
58、complex& operator+() /前綴 +real; +imag; return *this; complex operator+(int) /后綴 complex t = *this; +real; +imag; return t; ;1175.3 常規(guī)運(yùn)算符的重載特例:+和-第五章 運(yùn)算符重載類型轉(zhuǎn)換(type casting) 大體上可以分為以下幾類:標(biāo)量類型向標(biāo)量類型轉(zhuǎn)換。標(biāo)量類型向類類型轉(zhuǎn)換。類類型向標(biāo)量類型轉(zhuǎn)換。類類型向類類型轉(zhuǎn)換。1185.4 類型轉(zhuǎn)換第五章 運(yùn)算符重載類的構(gòu)造函數(shù)可以將標(biāo)量類型數(shù)據(jù)轉(zhuǎn)換為類類型數(shù)據(jù)。隱式的complex z = 5.6; /= z =
59、complex5.6顯式的:類的構(gòu)造函數(shù)被explicit說明 complex z = complex5.6; 1195.4 類型轉(zhuǎn)換5.4.1 標(biāo)量-類上述過程稱為“裝箱(boxing)”第五章 運(yùn)算符重載為類重載標(biāo)量轉(zhuǎn)換運(yùn)算符class complexpublic: operator double() return sqrt(real * real + imag * imag); ;complex c1, 2;double d = c; /= d = double(c) = d = c.operator double()1205.4 類型轉(zhuǎn)換5.4.2 類-標(biāo)量“拆箱(unboxing)”
60、函數(shù)不能有返回類型,但必須有return語句必須是成員第五章 運(yùn)算符重載示例class complexa; /forwardingclass complexpublic: operator class complexa(); /僅聲明;class complexapublic: operator class complex() ;complex:operator complexa() /實(shí)現(xiàn)1215.4 類型轉(zhuǎn)換5.4.3 類-類第五章 運(yùn)算符重載運(yùn)算符的特點(diǎn):是個(gè)雙目運(yùn)算符;數(shù)組對象是左操作數(shù),下標(biāo)是右操作數(shù)。表達(dá)式ai是個(gè)左值對象。根據(jù)上述特點(diǎn),重載的運(yùn)算符函數(shù)應(yīng)該具有如下特點(diǎn):重載為類的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 彩鋼房基礎(chǔ)防水施工方案
- 裝配式預(yù)留預(yù)埋施工方案
- 玻璃鋼除塵凈化塔施工方案
- 合盛包裝科技(徐州)有限公司玻璃瓶包裝裝潢及配套件加工項(xiàng)目環(huán)境影響報(bào)告表
- 保亭縣大件垃圾及園林垃圾破碎分揀及建筑垃圾轉(zhuǎn)運(yùn)調(diào)配場項(xiàng)目環(huán)評報(bào)告表
- 超高速切削機(jī)床項(xiàng)目風(fēng)險(xiǎn)識別與評估綜合報(bào)告
- 陽泉直埋式保溫管施工方案
- 場地平整及強(qiáng)夯施工方案
- 施工方案編制格式
- 湖北省黃岡市部分學(xué)校2024-2025學(xué)年九年級下學(xué)期入學(xué)化學(xué)試題(原卷版+解析版)
- 連接員題庫(全)題庫(855道)
- 工程安全管理組織機(jī)構(gòu)框架圖
- 新版現(xiàn)代西班牙語學(xué)生用書第一冊課后習(xí)題答案
- JCT533-2016 建材工業(yè)用鉻合金鑄造磨球
- 活動10《體驗(yàn)微視頻拍攝樂趣》第二課時(shí)-體驗(yàn)微視頻拍攝樂趣 第二課時(shí) 課件
- 淺談物業(yè)管理行業(yè)工程造價(jià)控制
- 社會工作-心理學(xué)視角下的校園欺凌認(rèn)知與對策研究論文
- 公文寫作規(guī)范及技巧
- 面神經(jīng)炎臨床路徑
- 月光奏鳴曲全面版
- 2022年湖北省中小學(xué)教師高級職稱專業(yè)水平能力測試模擬題
評論
0/150
提交評論