360 likes | 503 Views
// BINFILE.CPP #include <fstream.h> void main() { ofstream of("test2.dat", ios :: binary); int nArr[10]; for(int i = 0; i < 10; i ++) nArr[i] = i * i; of.write((char*)nArr, 10 * sizeof(int)); of.close(); }. void main() { ifstream inf("test2.dat", ios :: binary);
E N D
// BINFILE.CPP #include <fstream.h> void main() { ofstream of("test2.dat", ios :: binary); int nArr[10]; for(int i = 0; i < 10; i ++) nArr[i] = i * i; of.write((char*)nArr, 10 * sizeof(int)); of.close(); }
void main() { ifstream inf("test2.dat", ios :: binary); int n; while(1) { inf.read((char*)&n, sizeof(int)); if(inf.eof()) break; cout << n << " "; } cout << endl; inf.close(); } 该程序的输出为: 0 1 4 9 16 25 36 49 64 81
int Lookup(char* fname, int what, int num) { ifstream inf(fname, ios :: binary); int n, low = 0, hi = num - 1, mid, len = sizeof(int); while(low <= hi) { mid = (low + hi) / 2; inf.seekg(mid * len); inf.read((char*)&n, len); if(n == what) break; if(n < what) { low = (mid + 1) * len; else hi = (mid - 1) * len; }
inf.close(); if(low > hi) return -1; return(inf.tellg() - len); } 习题: 31,32,33
第14章 模板 模板(Template)是 C++ 语言代码重用和多态性的一个集中表现。模板是提供这样一个转换机制:由程序员定义一种操作或一个类,而该操作或类却可以适应几乎所有的数据类型。在一定意义上,模板类似宏定义或函数重载,但它书定更为简洁,使用更加灵活,适应性更强。 模板分函数模板和类模板。前者为程序员编写通用函数提供了 一种手段;而后者则为程序员设计通用类奠定了基础。
14.1 函数模板 14.1.1 定义模板函数 利用函数模板定义的函数叫做模板函数,定义模板函数应具有以下的一般形式: template<class T> type Function_Name(arg_list) { // Function_Body; } 其中:关键字 template 指出下面将要说明的是一个模板;而<class T> 则是该函数所要求的参数,这里的 class 与类无关,而是与参数名 T 一起指出:“这是一个用户定义的数据类型”,它与一对尖括号是模板语法的组成部分。
例:定义模板函数 // MAXMIN.H template<class T> T Max(T a, T b) { return (a > b) ? a : b; } template<class T> T Min(T a, T b) { return (a < b) ? a : b; }
定义模板函数时应注意: 1. 在模板的参数表中,至少得有一个参数的数据类型为模板的参数类型 T;模板函数的返回值的数据类型也可以为 T。 2. 模板可以带有多个不同数据类型的参数,比如: template<class T1, class T2, class T3> int f(T1 arg1, T2 arg2, T3 arg3) { //… } 3. 模板参数的数据类型也可以是已存在的数据类型,比如: template<class T, int n> T f(T arg) { int i = n; //… }
4. 函数可以带有模板中未给出的、已存在的数据类型的参数,比如: template<class T> T f(T arg, int n) { //… } 5. 模板函数的函数体中必须使用模板参数。
14.1.2 使用模板函数 调用模板函数与调用一般函数的方法无二致。 例:使用 Max()和 Min()模板函数 #include <iostream.h> #include "maxmin.h" void main() { int i = 3, j = 5; float f1 = 12.34, f2 = 23.45; cout << Max(i, j) << endl; cout << Min(f1, f2) << endl; cout << Max('a', 'b') } 程序的输出为: 5 12.34 b
14.2 类模板 14.2.1 定义模板类 利用类模板定义的类叫做模板类。定义模板类具有如下的一般形式: template<class T> class Class_Name { // Members; };
例:定义模板类 // ANYTYPE.H template<class T> class AnyType { private: T x, y; public: AnyType(T a, T b) : x(a), y(b) {} void SetX(T a) { x = a; } void SetY(T b) { y = b; } T GetX() { return x; } T GetY() { return y; } }; // End of ANYTYPE.H
上例中,模板类 AnyType 中所有成员函数均在类中定义成内联函数。实际上,与一般类相同,模板类中的任一成员函数均可以在类外定义。在类外定义成员函数的一般形式与定义模板函数基本相同: template<class T> type Class_Name<T> :: Func_Name(ages) { // Function_Body; } 请注意这里类名的写法:模板类与普通类的不同之处在于模板类的类名一定具有 Class_Name<T> 的形式。
例:定义一个栈模板类 // ANYSTACK.H #if !defined _ANYSTACK_H_ #define _ANYSTACK_H_ template<class T, int n = 10> class AnyStack { private: T Stack[n]; int TopMost; int Top; public: AnyStack() : TopMost(n), Top(0) {} int Push(T); int Pop(T&); }
template<class T, int n> int AnyStack<T, n> :: Push(T Elem) {if(Top == TopMost) // 栈已满 return 0; Stack[Top ++] = Elem; return 1; } template<class T, int n> int AnyStack<T, n> :: Pop(T& rElem) {if(Top == 0) // 栈为空栈 return 0; rElem = Stack[-- Top]; return 1; } #dneif
14.2.2 使用模板类 与一般类一样,在使用一个类时必须先行说明属于该类类型的对象(或指针)。然而,模板类对象的说明形式与一般类对象有所不同,说明模板类对象具有如下的一般形式: Class_Name<type> Obj_Name; 其中:type为任一已存在的数据类型(包括类类型)。
例:使用 AnyStack 模板类 #inclucd <iostream.h> #include "anystack.h" void main() { AnyStack<int> iStk; AnyStack<float 5> fStk; int i, iE; float fE; for(i = 1; i < 6; i ++) { iStk.Push(i); fStk.Push(i * 3.14); }
while(iStk.Pop(iE)) cout << iE << '\t'; cout << endl; while(fStk.Pop(fE)) cout << fE << '\t'; cout << endl; } 该程序的输出为: 1 2 3 4 5 3.14 6.28 9.42 12.56 15.70
H ^ ^ Prev Info Next 综合举例 问题 设计一个双链表类,并为其提供相应的公有接口。 分析 所谓双链表是指一种线性表,该表由一个个叫做结点(Node)的元素组成,各结点分别有两个指针:一个指向其前趋(Previous);一个指向其后继(Next)。如下图所示。
从上图可以看出:双链表的设计可以分为两部分——结点的设计和链表的设计。为了便于链表对结点的访问,可以将链表类设计成结点类的友元。从上图可以看出:双链表的设计可以分为两部分——结点的设计和链表的设计。为了便于链表对结点的访问,可以将链表类设计成结点类的友元。 结点的运算(操作)主要包括:创建结点、销毁结点、访问结点的信息(Info)域、访问结点的链域(Prev 或 Next)。 双链表的运算主要包括:创建一个空链表、销毁整个链表、在链表中插入一个结点、删除链表中的一个指定结点、在链表中查找一个指定内容的结点。其中插入操作又可以分为:在链表尾部插入(也叫追加)、在某一指定结点之前插入(称为前插入)、在某一指定结点之后插入(称为后插入)。同样,删除操作也可以分为:自身删除、前删除和后删除。
// OBJECT.H #if !defined _OBJECT_H_ #define _OBJECT_H_ class Object { public: Object() {} virtual ~Object() {} virtual int operator ==(Object&) = 0; virtual int operator >(Object&) = 0; virtual int operator <(Object&) = 0; virtual void Show() = 0; }; #endif
// NODE.H #include "object.h" class NODE { private: Object * Info; NODE *Prev, *Next; public: NODE() : Info(0), Prev(0), Next(0) {} ~NODE() { delete Info; } void SetInfo(Object& rObj) { Info = rObj; } Object* GetInfo() { return Info; } void ShowInfo() { Info.Show(); } friend class DLIST; };
// DLIST.H #if !defined _DLIST_H_ #define _DLIST_H_ #include "node.h" class DLIST { private: NODE *Head, *Tail; void DestroyList(); public: DLIST() : Head(0), Tail(0) {}
void AppendNode(NODE*); void InsertPrev(NODE*, NODE*); void InsertNext(NODE*, NODE*); NODE* DeleteNode(NODE*); NODE* DeletePrev(NODE*); NODE* DeleteNext(NODE*); NODE* Lookup(Object&); void ShowList(); void DestroyList(); ~DLIST() { DestroyList(); } }; #endif
n T H // DLIST.CPP #include "dlist.h" void DLIST :: AppendNode(NODE* node) { if(Head == 0) Head = Tail = node; else { Tail->Next = node; node->Prev = Tail; Tail = node; } }
void DLIST :: InsertPrev(NODE* node, NODE* pPos) { node->Prev = pPos->Prev; node->Next = pPos; pPos->Prev = node; node->Prev->Next = node; } void DLIST :: InsertNext(NODE* node, NODE* pPos) { 作为习题请同学自己编写; }
NODE* DLIST :: DeleteNode(NODE* node) { node->Prev->Next = node->Next; node->Next->Prev = node->Prev; node->Prev = node->Next = 0; return node; } NODE* DLIST :: DeletePrev(NODE* pPos) { return DeleteNode(pPos->Prev); }
NODE* DLIST :: DeleteNext(NODE* pPos) { return DeleteNode(pPos->Next); } void DLIST :: ShowList() { NODE* pnode = Head; while(pnode) { pnode->ShowInfo(); pnode = pnode->Next; } }
NODE* DLIST :: Lookup(Object& rObj) { NODE* pnode = Head; while(pnode) { if(*(pnode->Info) == rObj) // 调用重载了的关系运算符 return pnode; pnode = pnode->Next; } return 0; }
void DLIST :: DestroyList() { NODE *pnode = Head; while(pnode) { Head = pnode->Next; delete pnode->Info; delete pnode; pnode = Head; } } // End of DLIST.CPP
// COMPLEX.H #if !defined _COMPLEX_H_ #define _COMPLEX_H_ #include "object.h" class Complex : public Object { private: float Real; float Img; public: Complex() : Real(0), Img(0) {} Complex(float r, float i) : Real(r), Img(i) {} ~Complex() {}
void SetReal(float r) { Real = r; } void SetImg(float i) { Img = i; } float GetReal() { return Real; } float GetImg() { return Img; } virtual int operator ==(Object&); virtual int operator >(Object&); virtual int operator <(Object&); virtual void Show(); }; #endif // End of COMPLEX.H
// COMPLEX.CPP #include <iostream.h> #include "complex.h" int Complex :: operator ==(Object& rObj) { Complex &com = (Complex&)rObj; return (com.Real == Real && com.Img == Img); } int Complex :: operator >(Object& rObj) // 自编 int Complex :: operator <(Object& rObj) // 自编
void Complex :: Show() { cout << Real << " + " << Img << 'i' << endl; } // End of COMPLEX.CPP
// TESTLIST.CPP #include <iostream.h> #include "dlist.h" #include "complex.h" void main() { DLIST List; NODE *pn, node; Complex *pc, Key; for(int i = 1; i <= 5; i ++) { pc = new Complex(i * 3.5, i * 4.6); pn = new NODE; pn->SetInfo(pc);
该程序的输出为: 3.5 + 4.6i 7 + 9.2i 10.5 + 13.8i 14 + 18.4i 17.5 + 23i 3.5 + 4.6i 7 + 9.2i 14 + 18.4i 17.5 + 23i List.AppendNode(pn); } List.ShowList(); cout << endl; Key.SetReal(10.5); Key.SetImg(13.8); pn = List.Lookup(Key); if(pn) pn = List.DeleteNode(pn); List.ShowList(); delete pn; }