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、模板及智能指针
//智能指针包装了其它对象指针,对象指针能够是不论什么类型,它由模板类的參数指定
//智能指针在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] = '\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)
*/
浙公网安备 33010602011771号