首页 > 代码库 > C++关键知识
C++关键知识
《精通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、模板及智能指针 //智能指针包装了其他对象指针,对象指针可以是任何类型,它由模板类的参数指定 //智能指针在COM客户端广泛使用,用来自动管理引用计数 #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] = '\0'; strcat(ch, m_buffer); strcat(ch, string); temp = ch; return temp; } String String::operator+(String &string) { return operator+((char *)string); } char &String::operator[](int i) { size_t len = strlen(m_buffer); assert(i>=0 && i<len); return m_buffer[i]; } bool String::operator==(char *string) { if (m_buffer == NULL) { if (string == NULL) { return true; } return false; } if (string == NULL) { return false; } return strcmp(m_buffer, string)==0; } bool String::operator==(String &string) { return operator==((char *)string); } String &String::operator+=(char *string) { if (string == NULL) { return *this; } if (m_buffer == NULL) { *this = string; return *this; } size_t len = strlen(m_buffer) + strlen(string); char *ch = new char[len + 1]; ch[0] = '\0'; strcat(ch, m_buffer); strcat(ch, string); m_buffer = ch; return *this; } String &String::operator+=(String &string) { return operator+=((char *)string); } void Demo() { String str1("xiao hua"); String str2("yan yang"); cout<<(char *)str1<<endl; for (int i = 0; i < str2.Length(); i++) { cout<<str2[i]; } cout<<endl; if (str1 == str2) { cout<<"str1与str2相等!"<<endl; } else { cout<<"str1与str2不相等!"<<endl; } String str3 = str1 + str2; cout<<(char *)str3<<endl; str3 += str1; cout<<(char *)str3<<endl; getchar(); } //一元操作符的重载函数没有参数 //二元操作符的重载有一个参数 //运算符的第一个操作参数总是当前对象this //自增的自减运算符的重载 //(1)前置++或-- //重载格式: operator++或operator-- //(2)后置++或-- //重载格式: operator++(int)或operator--(int) */
作者:http://blog.csdn.net/lp310018931
C++关键知识
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。