《精通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)
*/