程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Some Tips On Using MFC and STL and Containers

Some Tips On Using MFC and STL and Containers

編輯:關於C語言
 

1.兩個輸入文件:grade.txt及grade2.txt. grade.txt每行如:"0211111001 張三豐 99"
grade2.txt也有多行,每行形如:"0201121002 周伯通 老玩童 100"
2.用已提供的MyStl.h文件。
3.定義一個輸出文件,名為“你的學號+result.txt“。
4.創立一個名為Homework.cpp的文件。
5.在Homework.cpp中用Grade 的CArray, CList, CMap, vector, list, queue, map分別做:
<A>讀入grade.txt, grade2.txt於容器(即上述CArray, Clist 等)。
<B>將內容輸出至輸出文件(見4)。
<C>如果容器可以排序,將內容排序,再將結果輸出至輸出文件。
<D>刪除所有grade==100的記錄,再將結果輸出至輸出文件。

問題一:MFC庫的使用

由於平常只是建立空文檔,很少使用到MFC庫。但當程序中使用到MFC的容器類之後,如果沒有選擇使用MFC庫,會在link時候報出"error LNK2001"錯誤。
解決辦法是在建立Win32 Console Application的時候在向導的第二個對話框裡選擇"Using MFC as shared dll"復選框。已經建立好工程的,在"工程"->"設置"->"常規"選項卡裡找到"Microsoft Fundation Class"下拉框,選擇"using MFC as shared dll"即可。

問題二:頭文件的包含關系

由於作業涉及到MFC和STL,很多東西老的庫和新的都會有沖突,還有命名空間的問題,最好對每個類別建立一個頭文件和源程序文件,能盡量的避免出錯。
我的方法是,用MFC來處理數據的程序為一個源文件,並在頭文件裡只包含和MFC有關的東西,其中要包含的系統頭文件有:
#include <afx.h> //包含許多基類的聲明,例如:CObject,CString
#include <afxtempl.h> //包含模板類的定義
#include <iostream.h> //標准輸入輸出流
#include <string.h> //包含字符串處理函數
#include <fstream.h> //文件輸入輸出流
用STL來處理數據的源程序的頭文件包括:
#include <fstream> //文件輸入輸出流,標准C++
#include <iostream> //標准輸入輸出流,標准C++
#include <string> //字符串,串處理函數,串模板,STL
#include <algorithm> //算法,STL
#include <vector> //向量模板,STL
#include <list> //列表模板,STL
#include <queue> //隊列模板,STL
#include <map> //散列表(准確的來說散列表是hash_map,但這裡暫且這麼稱呼)模板,STL
using namespace std; //使用標准名字空間
#pragma warning(disable:4786) //不提示4786號警告,因為VC6.0與標准C++的不全相容性,對長名有警告

問題三:類的定義

由於顯然性的兩個文件的關系,定義類的時候可以采用繼承的方法,注意變量盡量聲明成protected類型,這樣在派生類裡可以直接訪問父類的變量。其實在這裡並不是完全有必要把數據封裝起來,但封裝會有很大的好處。比如說,通過重載函數來增加程序的一致性和可讀性,重載運算符對算法的支持。下面是在MFC環境下的類定義,相應在標准C++環境下不同的地方主要是CString變為string,BOOL變為:bool,char*也可變為:string。
class cSwordsman
{
public:
cSwordsman(char* Sworder_ID = "",char* Sworder_NAME = "",int Sworder_SCORE = 0);
~cSwordsman();
CString GetId();
CString GetName();
int GetScore();
void SetId(char* Sworder_ID);
void SetName(char* Sworder_NAME);
void SetScore(int Sworder_SCORE);
BOOL operator<(cSwordsman& y);
BOOL operator>(cSwordsman& y);
BOOL operator==(cSwordsman& y);
void FileOut(ofstream& fout);
void ScreenOut();
protected:
CString id;
CString name;
int score;
};
class cLongSwordsman:public cSwordsman
{
public:
cLongSwordsman(char* Sworder_ID = "",char* Sworder_NAME = "",char* Sworder_MONIKER = "",int Sworder_SCORE = 0);
~cLongSwordsman();
CString GetMoniker();
void SetMoniker(char* Sworder_MONIKER);
void FileOut(ofstream& fout);//對父類成員函數的重載
void ScreenOut();
protected:
CString moniker;
};

問題四:文件輸入和輸出流的參數不同

文件輸入輸出流其實是一個類,平常所用的:ifstream fin("grade.txt",ios::in|ios::nocreate);其實是對象的初始化。所以在上面可以在FileOut函數的參數裡設為:ofstream& fout。這樣在函數裡就可以直接用fout輸出了,通過用ofstream對象的引用做函數參數,避免了頻繁的打開文件。
在<fstream.h>和<fstream>中對文件流的定義是相似但不同的,最主要的一個方面表現在打開參數上,<fstream.h>中定義的打開模式是ios::in(輸入)形式的參數,而<fstream>中是以ios_base::app(添加)形式的參數。
而且<fstream.h>和<fstream>的成員方法有些使用上差別很大,比如getline。

問題五:函數重載的使用減少工作量

比如由上面兩個類的定義,可以使處理相應的類型數據的函數使用相同的名字,而在參數中使用兩個不同的類引用作為參數,這樣就能通過參數的不同調用不同的函數,而函數名是相同的,減少記憶和出錯的可能。

問題六:運算符重載以使用已有算法

在STL的<algorithm>中定義了許多現成算法,比如:sort,就是根據類中"<"的重載來排序的。

問題七:文本文件的讀取

文本文件可以用標准輸入輸出流來讀,假如已經定義了ifstream fin("grade.txt",ios::in|ios::nocreate);,就可以像cin一樣讀取數據,但有時候可能需要更完善的方法,還可以用fin.getline來讀入一行,然後再用字符串處理函數對這和串進行處理。

問題八:STL中iterator的使用

iterator實際是一種類型的變量,定義的時候根據模板的不同而不同。在vector,list和queue中,可以把iterator當作指向成員類的指針,用iterator->PublicVar,來使用公有成員變量,用(*iterator).MemFunctions,來使用成員函數。但在map中要注意iterator指向的是一個pair,pair是map模板中定義的一個類,有兩個公有成員變量,first和second。其中iterator->first,代表使用的key,iterator->second才是模板成員類的對象。用iterator->second.MemFunctions,來調用成員函數。
 

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved