《精通MFC》第一章节整理复习
//c++编程技术要点 /* //1、虚函数及多态的实现 //演示多态技术 #include <iostream> using namespace std; void Demo(); int main() { Demo(); getchar(); return 0; } class Graphic { public: virtual void Draw(); }; //END CLASS DEFINITION Graphic void Graphic::Draw() { cout<<"绘制Graphic"<<endl; } class Line: public Graphic { public: virtual void Draw(); }; //END CLASS DEFINITION Line void Line::Draw() { cout<<"绘制Line"<<endl; } class Rect: public Graphic { public: virtual void Draw(); }; //END CLASS DEFINITION Rect void Rect::Draw() { cout<<"绘制Rect"<<endl; } class Text: public Graphic { public: virtual void Draw(); }; //END CLASS DEFINITION Text void Text::Draw() { cout<<"绘制Text"<<endl; } void Demo() { Graphic *g[3]; Line line; Rect rect; Text text; g[0] = &line; g[1] = ▭ g[2] = &text; for(int i = 0; i < 3; i++) { g[i]->Draw(); } cout<<endl; } */ /////////////////////////////////////////////////////////////////////////// //2、动态调用 //首先我们要知道。编译器会为每个有虚函数的类创建一个虚函数表,所以该类对象实例在内存中的 //布局分为两部分,第一部分为4字节,指向虚函数表的指针,剩下的部分是对象的数据。 //sizeof运算符包括指向虚函数表的指针的4个字节长度 /* #include <iostream> using namespace std; void Demo1(); void Demo2(); int main() { //Demo1(); Demo2(); return 0; } class V1 { private: int Size; public: int Size2; V1(); ~V1(); void DoShow(); virtual void Show(); }; V1::V1() { Size = 5; Size2 = 10; } V1::~V1() { Size = 0; Size2 = 0; } void V1::DoShow() { cout<<"Size2: "<<Size2<<endl; } void V1::Show() { cout<<"Size: "<<Size<<endl; } void Demo1() { //动态调用,用一个void *类型指针来调用实例对象 void *pObjt = NULL; V1 v1; int len = sizeof(V1); cout<<"len: "<<len<<endl; pObjt = new char[len]; *(int *)pObjt = *(int *)&v1; //① //这样的拷贝方式是浅拷贝。假设V1中包括指针。则仅拷贝指针本身而不拷贝批针所指的内容, //若想使用深拷贝,则须要在类定义中重载"="运算符, //这里的赋值操作仅仅会拷贝对象的数据,而不会复制指向虚函数表的指针 *(V1 *)pObjt = v1; ((V1 *)pObjt)->DoShow(); ((V1 *)pObjt)->Show(); //② //释放内存:先显示调用目标类的析构函数。释放对象的内存资源。然后delete为指针pObjt所分配的内存 ((V1 *)pObjt)->~V1(); //释放对象资源 delete pObjt; //释放指针所指向的资源 pObjt = NULL; //将指针置空 getchar(); } //对于非虚函数的调用。不要设置虚函数表指针就能够调用了(即上面的①和②能够同一时候删除。也不会出错)。但如 //果调用了虚函数,则必须保证pObjt所指的内存的前4个字节正确指向了目标类的虚函数表。//一般非常少用void *指针直接动态调用,而是声明一个跟目标类内存布局兼容的结构,该结构的前4个字节为DWORD_PTR //用来指高目标类的虚函数表,结构后面的是一系列的数据或成员声明(我们都知道函数是不占用内存的),且要保证结构 //的数据成员集合为目标类中数据成员集合的超集,并要求它们公共的部分排列一致。 //以下用结构体来取代void *类型指针 struct V2 { int m_vtbl; //虚函数表指针占位符 int size21; int size22; //后面的数据或成员都没有什么用 void MyShow(){} int size23; }; void Demo2() { V1 v1; V2 v2; v2.m_vtbl = *(int *)&v1; *(V1 *)&v2 = v1; ((V1 *)&v2)->DoShow(); ((V1 *)&v2)->Show(); getchar(); } */ /* //3、接口技术 //接口是一种特殊的抽象类,它的全部成员都是纯虚函数。且不包括不论什么的数据成员。这样指向接口的指针 //仅是一个指向虚函数表的指针,而不会有不论什么的数据,接口的虚函数指针将被拷贝到子类。子类负责实现 //这些虚函数 //一个类向它的友元类公开全部的数据和方法。
包括公有的。私有的和受保护的。
//接口演示,对COM框架的模拟 #include <iostream> using namespace std; void Demo(); int main() { Demo(); return 0; } //定义两个接口。当中IHello接口从IUnknown接口继承 class IUnknown { public: virtual void *QueryInterface(int IID) = 0; virtual void AddRef() = 0; virtual void Release() = 0; }; //END INTERFACE DEFINITION IUnknown class IHello: public IUnknown { public: virtual void Hello(char *szMsg) = 0; }; //END INTERFACE DEFINITION IUnknown #define IID_IUnknown 1 #define IID_IHello 2 int CLASID_CAT; //提前声明友类。訪问CAT类的私有构造函数 class Factory; //抽象基类 class HelloImplement: IHello { private: int m_nRef; protected: HelloImplement(); public: void *QueryInterface(int IID); void AddRef(); void Release(); virtual void Hello(char *szMsg) = 0; }; //基于引用计数的生存期管理 HelloImplement::HelloImplement() { m_nRef = 0; } void HelloImplement::AddRef() { m_nRef++; } void HelloImplement::Release() { m_nRef--; if (m_nRef == 0) { delete this; } } //接口查询 void *HelloImplement::QueryInterface(int IID) { if (IID == IID_IUnknown) { AddRef(); return (IUnknown *)this; } if (IID == IID_IHello) { AddRef(); return (IHello *)this; } return NULL; } //详细类 class Cat: public HelloImplement { private: char *m_szName; public: void Hello(char *szMsg); private: Cat(char *name); friend class Factory; //友元类 }; Cat::Cat(char *name) { int len = strlen(name); m_szName = new char[len + 1]; strcpy(m_szName, name); } void Cat::Hello(char *szMsg) { cout<<"m_szName: "<<m_szName<<endl; cout<<"szMsg: "<<szMsg<<endl; } //类工厂。创建对象实例 class Factory { public: static void *GetComObject(int CLASID); }; void *Factory::GetComObject(int CLASID) { if (CLASID == CLASID_CAT) { Cat *cat = new Cat("小猫"); //返回对象的IUnknown接口 return cat->QueryInterface(IID_IUnknown); } return NULL; } //演示接口 void Demo() { IUnknown *pIUnknown = (IUnknown *)Factory::GetComObject(CLASID_CAT); //查询其它接口 IHello *pIHello = (IHello *)pIUnknown->QueryInterface(IID_IHello); //释放接口 pIUnknown->Release(); pIHello->Hello("演示接口"); //释放接口 pIHello->Release(); getchar(); } //把类的构造函数声明为私有的来防止直接构造事实上例。
//假设对象实现了某个接口,则对象能够转化为接口指针 */ /* //4、模板及智能指针 //智能指针包装了其它对象指针,对象指针能够是不论什么类型,它由模板类的參数指定 //智能指针在COMclient广泛使用,用来自己主动管理引用计数 #include <iostream> using namespace std; void Demo(); int main() { Demo(); return 0; } class RefCount { private: int crefs; public: RefCount(); ~RefCount(); void upCount(); void downCount(); }; RefCount::RefCount() { crefs = 0; } RefCount::~RefCount() { cout<<"再见! "<<crefs<<endl; } void RefCount::upCount() { crefs++; cout<<"计数添加到: "<<crefs<<endl; } void RefCount::downCount() { crefs--; if (crefs == 0) { delete this; } else { cout<<"计数降低到: "<<crefs<<endl; } } class Sample:public RefCount { public: void doSomething(); }; void Sample::doSomething() { cout<<"做一些事情!"<<endl; } //用模板类来实现智能指针 template<class T> class Ptr { private: //内包括的对象指针,指针类型由模板參数指定 T *p; public: Ptr(T *p_):p(p_)//设置内部指针 { //添加计数 p->upCount(); } //析构函数降低计数 ~Ptr() { p->downCount(); } //运算符重载 //重载类型转换符 operator T*(void) { return p; } //*重载 T &operator *(void) { return *p; } //->重载 T *operator->(void) { return p; } //=重载 //原来指向的计数减1,新指向的对象的计数加1:引用计数的基本原则 Ptr & operator=(T *p_) { p->downCount(); p = p_; p->upCount(); return *this; } //=重载 Ptr & operator=(Ptr<T> &p_) { return operator = ((T *)p_); } }; //演示表示智能指针的模板类 void Demo() { Ptr<Sample> p = new Sample; Ptr<Sample> p2 = new Sample; p = p2; //p的引用计数将自己主动变为0。并会自己主动销毁 p->doSomething(); //利用*操作符调用 (*p2).doSomething(); //利用T *操作符调用 ((Sample *)p)->doSomething(); return ; //p2和p超过范围。析构函数将被调用,从而downCount也被调用 //p2将被销毁 } */ /* //5、重载 //一般而言。重载有以下几种使用方法: //(1)在同一个类中定义多个同名的方法。这些方法具有不同的參数列表 //(2)子类重写父类的虚方法 //(3)子类重写父类的非虚方法(覆盖) //以下演示运算符重载 #include <iostream> #include <cassert> using namespace std; void Demo(); int main() { Demo(); return 0; } class String { private: char *m_buffer; public: //构造函数 String(){m_buffer = NULL;} String(char *string); String(String *str); String(String &str); ~String(){delete m_buffer;} //运算符重载 String &operator=(char *string); String &operator=(String &string); String operator+(char *string); String operator+(String &string); char &operator[](int); operator char*(){return m_buffer;} bool operator==(char *string); bool operator==(String &string); String &operator+=(char *string); String &operator+=(String &string); int Length(){return strlen(m_buffer);} }; String::String(char *string) { if (string == NULL) { m_buffer = NULL; return; } size_t len; len = strlen(string); m_buffer = new char[len+1]; strcpy(m_buffer, string); } String::String(String &string) { char *str = (char *)string; if (str == NULL) { m_buffer = NULL; return; } size_t len = strlen(str); m_buffer = new char[len + 1]; strcpy(m_buffer, str); } String &String::operator=(char *string) { if (string == NULL) { delete this; m_buffer = NULL; return *this; } if (m_buffer != NULL) { delete m_buffer; } int len = strlen(string); m_buffer = new char[len + 1]; strcpy(m_buffer, string); return *this; } String &String::operator=(String &string) { return operator=((char *)string); } String String::operator+(char *string) { if (string == NULL) { return *this; } String temp; if (m_buffer == NULL) { temp = string; return temp; } size_t len = strlen(m_buffer) + strlen(string); char *ch = new char[len + 1]; ch[0] = '