#
说明:相关技术参考自: 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: ... };
以下调用就不写了,你懂得的。
|