#
說明:相關技術參考自: http://www.cublog.cn/u/18517/showart_241240.html上面這個,寫的真的很不錯,通俗易懂。推薦大家去看下。下面是看完上面的文章后,自己嘗試的:
//智能指針聲明及實現
/************************************************************************/ /** 智能指針聲明 /************************************************************************/
#pragma once
#include <iostream> #include <stdexcept> using namespace std;
#ifndef TEST_SMARTPTR #define TEST_SMARTPTR #endif
template < class T > class TSmartPtr { public: //默認構造函數 TSmartPtr(T* pTObject = NULL) : m_pTObject(pTObject), m_pCount(new int(1)) {} //拷貝構造函數 TSmartPtr(const TSmartPtr& src) : m_pTObject(src.m_pTObject), m_pCount(src.m_pCount) { ++(*m_pCount); } //析構函數 virtual ~TSmartPtr() { #ifdef TEST_SMARTPTR cout << "SmartPtr Object Free." << endl; #endif DoDecUseCount(); } //=重載 TSmartPtr& operator = (const TSmartPtr& rhs) { // self-assigning is also right ++*rhs.m_pCount; //源智能指針的引用計數增1 DoDecUseCount(); //目標智能指針的引用計數減1。此非常有必要。因為該指針既然要指向rhs, //則說明它就不再想去管理自身原本的指針對象了。因此需要減1() //在自身引用計數減1后,有可能自身原本維護的指針對象會被釋放掉,也有可能不會。 //(因為,先前所管理的對象,有可能還有其他的智能指針對象在維護著了。) //因此,上面這兩句才是精髓。 m_pTObject = rhs.m_pTObject; m_pCount = rhs.m_pCount; return *this; } //->重載 T* operator -> () { if (NULL != m_pTObject) return m_pTObject; throw runtime_error("access through NULL pointer"); } const T* operator -> () const { if (NULL != m_pTObject) return m_pTObject; throw runtime_error("access through NULL pointr"); } //*重載 T& operator * () { if (NULL != m_pTObject) return *m_pTObject; throw runtime_error("dereference of NULL pointer"); } const T& operator * () const { if (NULL != m_pTObject) return &m_pTObject; throw runtime_error("dereference of NULL pointer"); } private: //引用計數減1 void DoDecUseCount(void) { if (0 == --*m_pCount) { if (NULL != m_pTObject) { delete m_pTObject; m_pTObject = NULL; } delete m_pCount; m_pCount = NULL; } } T* m_pTObject; int* m_pCount; } //調用
/************************************************************************/ /** 智能指針 /************************************************************************/
// SmartPointerStu.cpp : Defines the entry point for the console application. //
#include "stdafx.h"
#include "SmartPointer.h" #include <iostream> using namespace std;
//一個測試智能指針的類 class CMyTestClass { public: CMyTestClass() { cout << "A CMyTestClass Object was created." << endl; } virtual void Print(void) { cout << "CMyTestClass Print()." << endl; } virtual void Show(void) { cout << "CMyTestClass Show()." << endl; } ~CMyTestClass() { cout << "A CMyTestClass Object was destroied." << endl; } };
class CMyTestSubClass : public CMyTestClass { public: CMyTestSubClass() { cout << "A CMyTestSubClass Object was created." << endl; } virtual void Print(void) { cout << "CMyTestSubClass Print()." << endl; } void SubShow(void) { cout << "Sub Show()." << endl; } ~CMyTestSubClass() { cout << "A CMyTestSubClass Object was destroied." << endl; } };
int _tmain(int argc, _TCHAR* argv[]) { try { TSmartPtr<CMyTestClass> t; //因為沒有給t傳個CMyTestClass對象的指針參數進去。所以會出異常。 t->Print(); } catch(const exception& err) { cout << err.what() << endl; } //上面這個已經測試通過了。結果正確。 //-------------------------------------- TSmartPtr<CMyTestClass> t1(new CMyTestClass); t1->Print(); //上面這個測試->重載的操作符的正確性。測試結果是正確的。 TSmartPtr<CMyTestClass> t2(t1); t2->Print(); //上面這個測試拷貝構造函數的正確性。測試結果是正確的。 TSmartPtr<CMyTestClass> t3(new CMyTestClass); t3 = t2; (*t3).Print(); //上面這個測試=重載的操作符的正確性。測試結果也是正確的。
TSmartPtr<CMyTestSubClass> ts4(new CMyTestSubClass); ts4->Print(); ts4->SubShow(); ts4->Show(); TSmartPtr<CMyTestSubClass> ts5(ts4); ts5->SubShow(); TSmartPtr<CMyTestSubClass> ts6 = ts5; ts6->Print(); //上面測試一下帶有繼承關系的類指針對象的智能指針使用。測試結果也是正確的。
system("pause"); return 0; }
// TemplateStu.cpp : Defines the entry point for the console application. //
#include "stdafx.h"
#include <iostream> using namespace std;
/************************************************************************/ /** 函數模板 /************************************************************************/ template<class T> T min___(T t1, T t2) { return t1 < t2 ? t1 : t2; }
template<typename T> T max___(T t1, T t2) { return t1 > t2 ? t1 : t2; }
/************************************************************************/ /** 類模板 /************************************************************************/ template<class TA, class TB> class TShowClass { private: TA* m_pObjA; TB* m_pObjB; public: TShowClass(TA* pA, TB* pB); void Show(void); };
//類模板的構造函數 template<class TA, class TB> TShowClass<TA, TB>::TShowClass(TA* pA, TB* pB) { this->m_pObjA = pA; this->m_pObjB = pB; }
//Show函數 template<class TA, class TB> void TShowClass<TA, TB>::Show() { int addA = 10000; int addB = 20000; cout << addA << endl; cout << addB << endl; }
class CClassA {
}; class CClassB {
};
int _tmain(int argc, _TCHAR* argv[]) { /************************************************************************/ /** 函數模板的調用(其實就跟變通模板的調用是一樣的) /************************************************************************/ int i = 10, j = 11; float f1 = 9.0f, f2 = 11.1f; char c1 = 'b', c2 = 'Q'; cout << min___(i, j) << endl; cout << min___(f1, f2) << endl; cout << min___(c1, c2) << endl;
cout << endl; cout << max___(i, j) << endl; cout << max___(f1, f2) << endl; cout << max___(c1, c2) << endl;
/************************************************************************/ /** 類模板的調用 /************************************************************************/ CClassA ObjA; CClassB ObjB; //TShowClass<CClassA, CClassB> ShowClassObj(&ObjA, &ObjB); //ShowClassObj.Show(); //上面兩行調用是OK的。現在再試下創建一個類模板的指針對象 typedef TShowClass<CClassA, CClassB> TSC; TSC* pShowClassObj = new TSC(&ObjA, &ObjB); pShowClassObj->Show(); delete pShowClassObj; pShowClassObj = NULL;
/************************************************************************/ /** 模板使用總結: /** 1) 不論是函數模板還是類模板。都必須以:template<class TA[, class TB, ]>[的內容是可選的,但至少要有一個] /** 2) 對于函數模板,則自1)步驟后,剩下的同寫一個普通函數的步驟是一模一樣的。 /** 3) 對于類模板,則自1)步驟后,剩下的同寫一個普通的類的步驟是一模一樣的。 /** 4) 對于類模板,它們的具體cpp實現,需要注意:普通類的實現前只是需要加上返回類型及類型前綴即可。而 /** 對類模板的具體實現卻是: /** template<class TA, class TB> /** TShowClass<TA, TB>::TShowClass(TA* pA, TB* pB){ } /** 與 /** template<class TA, class TB> /** void TShowClass<TA, TB>::Show(){ } /** 也就是說,cpp的具體實現的前綴不是以前的類類型,而是類模板類型 /** /** 5) 擴展:按上面的測試及理解,說明智能指針,則是在類模板內部維護一個具體實現對象的指針。詳細見智能指針的學習演示 /************************************************************************/
system("pause"); return 0; }
Memento模式 該模式的出現,主要是為了讓用戶擁有“撤銷”的操作。好給用戶有個恢復先前狀態的權力。其主要思想就是將對象(假設其類型為:ClassA)的先前狀態記錄起來(當然自己得管理好)。在需要時,用此恢復。根據此思路,當然實現方法就多種多樣。下面參考設計模式資料中的c++代碼。(覺得此代碼設計還是挺有道理的。因為對Memento類來說,除了ClassA的對象外,其他類型的對象都不需要,且也不應該能訪問到。因此,在具體實現上,它用了友元的技術)。
typedef std::string State;
class COperationsMemento { //其實更強的,可以將該類設計成。可以維護一組狀態的。這樣,就可以支持 //任意恢復到先前的第N種狀態。就好似photoshop的層的那樣的撤銷。 //為說明思想,此暫時只維護一個狀態。 private: State GetState(void) { return this->_sta; } void SetState(const State& state) { this->_sta = state; } // some code here private: State _sta; };
class COperationSteps { public: friend class COperationsMemento; COperationSteps() { this->m_pMemento = NULL; this->_sta = "normal"; } COperationSteps(COperationsMemento* pMemento) { this->m_pMemento = pMemento; this->_sta = "normal"; } virtual ~COperationSteps() { if (m_pMemento != NULL) { delete m_pMemento; m_pMemento = NULL; } } //存儲狀態(即:保存狀態) void SaveState(void) { if (m_pMemento == NULL) { m_pMemento = new COperationsMemento(); } m_pMemento->SetState(this->_sta); } //恢復狀態 void RestoreState(COperationsMemento* pMemento = NULL) { if (pMemento != NULL) { this->_sta = pMemento->GetState(); } else { this->_sta = m_pMemento->GetState(); } }
private: COperationsMemento* m_pMemento; //需要維護,因為該狀態,是自己私有的 State _sta; };
// FileOp.cpp : Defines the entry point for the console application. //
#include "stdafx.h"
//要用ifstream與ofstream進行文件的輸入與輸出操作,必須包含此頭文件 #include <fstream> #include <iostream> #include <stdio.h>//FILE需要
int _tmain(int argc, _TCHAR* argv[]) { //技術扶自: http://www.mini188.com/showtopic-954.aspx
/************************************************************************/ /** 輸入文件流 ofstream /************************************************************************/ /* //聲明文件輸入的操作對象(輸出流對象) std::ofstream fout; //打開一個文件,提示:如果Output.txt文件不存在,則系統會自動為你創建一個 fout.open("Output.txt"); //對文件進行寫操作。 fout << "This is a first line." << "\n"; fout << "This is a second line." << "\n"; int num = 150; char name[] = "John Doe"; fout << "Here is a number: " << num << "\n"; fout << "Now here is a string: " << name << "\n";
//將文件流內容保存到硬盤 fout.flush(); //關閉文件流 fout.close(); */
/************************************************************************/ /** 輸入文件流 ifstream 12 GameDev 15.45 L This is really awesome! /************************************************************************/ /* std::ifstream fin("Input.txt"); int number; float real; char letter, word[8]; fin >> number >> word >> real >> letter; char sentence[1000]; fin.getline(sentence, 1000);
fin.close(); */
/************************************************************************/ /** 文件流操作 fstream /************************************************************************/ // std::fstream fFile; // fFile.open("Output.txt", std::ios::in | std::ios::out); //fFile.open("無線iPhone平臺開發基礎培訓交流圈.jpg"); //經測試,非文本文件資源是打不開的。 //將整個文件的內容讀取出來,并顯示 //注意:用這種方法讀出來的,都是忽略空格與換行符的 // if (fFile.is_open()) // { // char letter; // //while (fFile.good() && !fFile.eof()) // while (!fFile.eof()) //用這個與上面那個都是一樣的效果 // { // fFile >> letter; // if (fFile.eof()) // break; // std::cout << letter << std::endl; // } // getchar(); // }
//注意:用這種方法讀限出來的,都是沒忽略末尾的換行符的 // if (fFile.is_open()) // { // char line[2048]; // while (fFile.good() && !fFile.eof()) // { // fFile.getline(line, 2048); // static int count = 0; // if (count < 3) // { // count += 1; // fFile.seekg(0, std::ios::beg); //這個是改變讀的指針位置。如果是想改變寫的指針位置用fFile.seekp(0, std::ios::beg/end); // } // std::cout << line << std::endl; // } // // //將第一行的字符串改:"The first line string is changed." // fFile.seekp(0, std::ios::beg); // //fFile << "The first line string is changed."; //寫內容不是這樣寫的。如果是ofstream可以這么寫。但對于fstream需要用下面的方法來寫。測試結果發現,仍是寫不進去 // //char* pszTempForWrite = "The first line string is changed."; // //fFile.write(pszTempForWrite, strlen(pszTempForWrite)); // fFile.seekg(0, std::ios::beg); // fFile.getline(line, 2048); // std::cout << line << std::endl; // getchar(); // }
// //* fstream的其他一些方法 // //read方法 // char* pszOutputFileText = NULL; // fFile.seekg(0, std::ios::end); // int nSize; // nSize = fFile.tellg(); // //std::cout << fFile.tellg() << std::endl; // //用read方法一次性將整文件給讀取出來(注意:這些讀出來后,末性居然會帶了一個亂碼。這個郁悶。) // pszOutputFileText = new char[nSize + 1]; // fFile.seekg(0, std::ios::beg); // fFile.read(pszOutputFileText, nSize); // pszOutputFileText[nSize] = '\0'; // std::cout << pszOutputFileText << std::endl; // delete [] pszOutputFileText; // getchar(); // // fFile.close();
/************************************************************************/ /** 二進制文件的讀寫 /************************************************************************/
/************************************************************************/ /** 字符串長度 /************************************************************************/ // char* pszString = "Hello"; // std::cout << strlen(pszString) << std::endl; //輸出5 // // std::string sString = "Hello"; // std::cout << strlen(sString.c_str()) << std::endl;//輸出5 // // char szTest[5] = { 'H', 'e', 'l', 'l', 'o' }; // std::cout << szTest[5] << std::endl; //越界了,所以會報。 // getchar();
/************************************************************************/ /** 使用FILE類對文件進行操作 (FILE在stdio.h中 /************************************************************************/ FILE* materialFile = fopen("DefaultObjectStd.material", "r"); if (materialFile == NULL) { std::cout << "Open the file \"DefaultObjectStd.material\" failure." << std::endl; return 0; }
const int MAX_COUNT =2048; char everyline[MAX_COUNT] = { '\0' }; while (fgets(everyline, MAX_COUNT, materialFile)) { std::cout << everyline; //注意:通過fgets()函數讀取出來的定符串,末尾是帶有換行符的。這與上面的是不一樣的。 }
//取得文件的長度(即:文件的大小) int nMaterialFileSize; fseek(materialFile, 0, SEEK_END); nMaterialFileSize = ftell(materialFile); std::cout << std::endl << nMaterialFileSize << std::endl; getchar();
fclose(materialFile);
return 0; }
說明: 本文來自CSDN博客:http://blog.csdn.net/goodluckyxl/archive/2005/01/19/259851.aspx
強制轉化四種類型可能很多人都常常忽略就象我一樣,但是有時還是比較有用的。不了解的建議看看,一些機制我也不是十分了解,只是將一些用法寫出來讓大家看看。
強制轉化無論從語法還是語意上看,都是c++中最難看的特征之一。但是基于c風格的轉化的語義的不明確性及其一些潛在問題。強制類型轉化最終還是被c++接受了。 1.static_cast運算符號 static_cast<T>(e),stroustrup讓我們可以把它看成隱含轉換的顯示的逆運算。這個是有一定道理的,基于隱式轉化的對象類型我們可以使用static_cast轉化運算符號。它是靜態的檢測,無法運行時檢測類型,在繼承中尤為突出。 使用范圍 <1>用于所有系統類型之間轉化,不能用于系統類型指針類型轉化 double t_d = 0; int t_i= static_cast<int>(t_d); //是合法的轉化 而企圖將double*->int*是不允許的 <2>用于繼承類之間的轉化(含指針),不能用于其他沒有隱式轉化的對象類型之間的轉化 繼承舉例: class x { }; class y: public x { }; 使用:x t_o_x; y t_o_y = static_cast<y>(t_o_x); //x* y*轉化也可以進行因為x,y繼承關 //系,類型可以自動隱式轉化使用 隱式轉化舉例: class x { }; class y {
public: y( x i_x ) {} }; x t_o_x; y t_o_y = static_cast<y>(t_o_x); //大家看到y構造函數可以對于x類型隱式轉化 //所以可以將x->y,如果企圖將y->x會報錯 2.reinterpret_cast 運算 主要用于對于類型指針類型的強制轉化,some_type* -> special_type*這樣轉化,類型信息可以是不完全的。它允許將任意指針轉化到其他類型指針,也允許任意整數類型到任意指針類型轉化(BT)。這樣導致的結果是極其不安全的,不能安全的應用于其他目的,除非轉化到原來類型。 <1> 使用所有整形可以轉化為任意類型的指針(指針是4字節的long的東東,那么機器就認為同類型就是可以轉化) int c; x* p = reinterpret_cast<x*>(c); //x是自定義的任意類型,當然包括系統類型 <2> 可以對于任意類型指針之間轉化 y* c; x* p = reinterpret_cast<x*>(c);//x,y代表所有自定義或系統類型 大家可以看到reinterpret_cast的轉化是極度的不負責任的,他只管轉化不檢測是否可以轉化。 <3> const_cast運算符號 這個很簡單從名字大家可以看出來,僅僅為了去掉或著加上const修飾符號。但是對于本身定義時為const的類型,即使你去掉const性,在你操作這片內容時候也要小心,只能r不能w操作,否則還是會出錯。 const char* p = "123"; char* c = const_cast<char*>(p); c[0] = 1; //表面上通過編譯去掉了const性,但是操作其地址時系統依然不允許這 //么做。這是一個漏洞吧 <4> dynamic_cast運算符號 Scott Mayers將其描述為用來執行繼承體系中:安全的向下轉型或者跨系轉型動作。也就是說你可以,用dynamic_cast將 指向base class的指針或引用轉型為 指向子類的對象的指針或引用。 class B {}; //polymorphic類型含virtual才能dynamic_cast class D: public B {} void f( B* pb ) { D* pd1 = dynamic_cast<D*>(pb);//如果pb為d類型正確返回,如果不是返回0 D* pd2 = static_cast<D*>(pb); //不管怎么樣都返回指針有可能指向不合適的對 //象,因為static僅僅靜態檢測,不能得到運 //行時對象的信息是否真正為D類型 }
反正大家在使用知道怎么用就ok了,c++強制轉化在模板中還是非常有用的,其他時候本人也喜歡用c的轉化方便。^_^
聲明:
1 /************************************************************************/ 2 /** 系統全局函數 3 /************************************************************************/ 4 5 #pragma once 6 7 #include <string> 8 9 // 取得應用程序路徑(末尾帶 '\' 的) 10 CString ExtractFilePath(void); 11 // 取得應用程序路徑(末尾不帶 '\' 的) 12 CString ExtractFileDir(void); 13 // 取得指定文件的目錄(參數為文件的完整路徑,返回值末尾不帶 '\' 的) 14 CString GetFileDir(const CString& csFullFileName); 15 // 取得指定文件的目錄(參數為文件的完整路徑,返回值末尾帶 '\' 的) 16 CString GetFilePath(const CString& csFullFileName); 17 // 將CString轉換成string(將Unicode串轉換成Ansi(返回string)) 18 std::string ConvertW2A(const CString& csString); 19 // 將路徑中的指定字符用另外的指定字符替換,并返回(string) 20 std::string StringReplace(const char* pszString, const char cSourceChar, const char cDestChar); 實現:
1 #include "stdafx.h" 2 #include "GlobalFunction.h" 3 #include <atlconv.h> 4 5 CString ExtractFileDir(void) 6 { 7 CString csResult; 8 WCHAR pszExeFullPath[MAX_PATH]; 9 ::GetModuleFileName(NULL, pszExeFullPath, MAX_PATH); 10 csResult = pszExeFullPath; 11 int iPos = csResult.ReverseFind('\\'); 12 csResult = csResult.Left(iPos); 13 return csResult; 14 } 15 16 CString ExtractFilePath(void) 17 { 18 CString csResult = ExtractFileDir(); 19 if (csResult.GetLength() > 0) 20 return csResult + L"\\"; 21 return csResult; 22 } 23 24 CString GetFileDir(const CString& csFullFileName) 25 { 26 if (!::PathFileExists(csFullFileName)) 27 return CString(L""); 28 29 CString csResult(csFullFileName); 30 int iPos = csResult.ReverseFind('\\'); 31 csResult = csResult.Left(iPos); 32 return csResult; 33 } 34 35 CString GetFilePath(const CString& csFullFileName) 36 { 37 CString csResult = GetFileDir(csFullFileName); 38 if (csResult.GetLength() > 0) 39 csResult + "\\"; 40 return csResult; 41 } 42 43 std::string ConvertW2A(const CString& csString) 44 { 45 USES_CONVERSION; 46 return std::string(W2A(csString)); 47 } 48 49 std::string StringReplace(const char* pszString, const char cSourceChar, const char cDestChar) 50 { 51 if (strlen(pszString) == 0) 52 return std::string(""); 53 const UINT iLen = strlen(pszString) + 1; 54 char* pszTargetString = new char[iLen]; 55 //char pszTargetString[iLen]; 56 try 57 { 58 strncpy(pszTargetString, pszString, iLen); 59 for (int iIndex = 0; iIndex != iLen; iIndex++) 60 { 61 if (pszTargetString[iIndex] == cSourceChar) 62 pszTargetString[iIndex] = cDestChar; 63 } 64 delete [] pszTargetString; 65 return std::string(pszTargetString); 66 } 67 catch ( ) 68 { 69 delete [] pszTargetString; 70 return std::string(""); 71 } 72 }
該模式也相對簡單。其主要處理的是這類問題:當系統或某些模塊已經成形后,突然需要增加某些功能。而這些功能的增加 在現有的對象中,暫時沒有辦法處理。同時,卻發現,該功能,其實另一模塊的對象卻可以處理的了。因此,就希望能夠在不修改原 有操作及系統結構的情況下,就自然而然地將該功能實現出來。此時,就可以使用Adapter來處理之。(注:在此,我們強調的是不 去修改原有系統的結構的情況下)。 就上述問題,Adapter模式有兩種解決方法。一種是通過對象適配來解決。另一種是通過類適配來解決。所謂的對象適配,指 的是,通過引入具有我們需要功能接口的對象(設類為X),在實現處理過程中,我們使用的是X的功能接口,以此來達到我們的需求。 而類適配,則指的是,產生一個新類,讓該新類,繼承自X類,則自然,該新類就會有了X的相關接口。下面看下,這兩種適配的代碼。
對象適配 class X { public: ... virtual func(...); };
class ObjAdapterObject : public ... { public: void func(...) { if (m_pXObj != NULL) m_pXObj->func(...); } private: X* m_pXObj; };
類適配 class X的聲明及定義同上。
class ClassAdapterObject: public X, public ... { public: ... };
以下調用就不寫了,你懂得的。
|