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)
*/
C++关键知识的更多相关文章
- iOS之UI--通讯录的实例关键知识技术点积累
通讯录的实例关键知识技术点积累 效果展示: 作为博文笔记,既然是笔记,目的是为了能够以后做这个项目能够快速上手,如果这是我下一次阅览这个博文笔记,那么我应该先空手从零开始做,需求也就是这个项目的展示效 ...
- 在react native用到的javascript 的一些关键知识(整理中)
发现了一个讲解javascript的好网站,分享一下,讲的非常棒! 注意,这些文章都可以选择中文进行阅读! 下面这个连接是关于prototype的: https://developer.mozilla ...
- android关键知识
1.handler 与Looper 与MessageQueue .Message关系 handler:是处理主线程(ui线程)处理耗时操作的线程,通过post message到MessageQueue ...
- Kubernetes集群部署关键知识总结
Kubernetes集群部署需要安装的组件东西很多,过程复杂,对服务器环境要求很苛刻,最好是能连外网的环境下安装,有些组件还需要连google服务器下载,这一点一般很难满足,因此最好是能提前下载好准备 ...
- Promise关键知识
异步是ES6中使用频率最高的特性之一,也是面试中经常会被问到的问题,特此整理了相应的笔记 一.Promise的三种状态 pending-异步操作没有结束 fulfilled-异步操作已成功结束,最常见 ...
- 2 js的20/80关键知识
1. 2 var a = 1; undefined a 1 alert(a); undefined var b = true; var c = "Hi"; undefined al ...
- java关键知识汇总
1.泛型理解 2.java或Java框架中常用的注解及其作用详解 3.三层架构和MVC的区别 4.jdk1.8手册(提取码:bidm) 5.Rocketmq原理&最佳实践 6.spring入门 ...
- Vue-Router的Hash说起的URL相关知识
最近被问到VueRouter的两种模式的区别,答:Hash模式url上有#号,History模式url上没有#.完! 也不知道这么回答对不对,就看了看资料,发现也就是这个意思吧! Vue-Router ...
- 容器化之路Docker网络核心知识小结,理清楚了吗?
Docker网络是容器化中最难理解的一点也是整个容器化中最容易出问题又难以排查的地方,加上使用Kubernets后大部分人即使是专业运维如果没有扎实的网络知识也很难定位容器网络问题,因此这里就容器网络 ...
随机推荐
- Kubernetes+Jenkins+Nexus+Gitlab进行CI/CD集成
前面已经完成了 二进制部署Kubernetes集群,下面进行CI/CD集成. 一.流程说明 应用构建和发布流程说明: 1.用户向Gitlab提交代码,代码中必须包含Dockerfile: 2.将代码提 ...
- ReverseEngineerCodeFirst 自定义模板
1.在你要生成的项目里面在根目录下面添加CodeTemplates文件夹,并在该文件夹下面创建子文件夹ReverseEngineerCodeFirst 2.在ReverseEngineerCodeFi ...
- Laravel5.1学习笔记4 控制器
HTTP 控制器 简介 基础控制器 控制器中间件 RESTful 资源控制器 隐式控制器 依赖注入和控制器 路由缓存 简介 除了在单一的 routes.php 文件中定义所有的请求处理逻辑之外,你可能 ...
- CSS的常用属性(二)
盒子模型之边框 border-(top/bottom/left/right)-style: solid 边框的风格 如(solid 实线,dotted 点线,dashed 虚线) border-top ...
- 使用T-sql建库建表建约束
为什么要使用sql语句建库建表? 现在假设这样一个场景,公司的项目经过测试没问题后需要在客户的实际环境中进行演示,那就需要对数据进行移植,现在问题来了:客户的数据库版本和公司开发阶段使用的数据库不兼容 ...
- 数据库 'tempdb' 的事务日志已满。若要查明无法重用日志中的空间的原因
最常的做法: --1.清空日志 DUMP TRANSACTION tempdb WITH NO_LOG --2.截断事务日志: BACKUP LOG tempdb WITH NO_LOG --3.收缩 ...
- T-SQL查询高级--理解SQL SERVER中非聚集索引的覆盖,连接,交叉和过滤
写在前面:这是第一篇T-SQL查询高级系列文章.但是T-SQL查询进阶系列还远远没有写完.这个主题放到高级我想是因为这个主题需要一些进阶的知识作为基础..如果文章中有错误的地方请不吝指正.本篇文章 ...
- Scala类型系统——高级类类型(higher-kinded types)
高级类类型就是使用其他类型构造成为一个新的类型,因此也称为 类型构造器(type constructors).它的语法和高阶函数(higher-order functions)相似,高阶函数就是将其它 ...
- PAT_A1126#Eulerian Path
Source: PAT A1126 Eulerian Path (25 分) Description: In graph theory, an Eulerian path is a path in a ...
- 分享接口管理平台 eoLinker AMS 线上专业版V3.0,只为更好的体验,了解一下?
不知不觉中,eoLinker AMS从2016年上线至今已经三个年头,按照一年一个大版本的迭代计划,我们终于迎来了eoLinker AMS 专业版3.0. AMS产品也从最初专注于API文档管理,成长 ...