显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Mihooke's blog

IT之恋

 
 
 
 
 
 

[置顶] 关于mihooke这个人

2015-4-30 23:20:51 阅读88 评论0 302015/04 Apr30

本人网名Mihooke,源自航海王里的原七武海之一"鹰眼"---乔拉可尔·米霍克,甚喜之,遂取之音译英文于自用。

Mihooke是茫茫猿类中的一枚C++ developer ,目前正在成长中,努力学习各种技术!

联系我:

QQ:1733133832E-mail:sadandeduoluozhich@163.com         mihooke@hotmail.com

技术宅们,有兴趣一起交流吧!

作者  | 2015-4-30 23:20:51 | 阅读(88) |评论(0) | 阅读全文>>

红黑树介绍

2017-3-1 18:35:39 阅读9 评论0 12017/03 Mar1

红黑树,一种二叉查找树。

二叉查找树,有如下性质:

若任意节点的左子树不为空,则左子树的值均小于它的根节点的值若任意节点的右子树不为空,则右子树的值均大于它的根节点的值任意节点的左、右子树均为二叉查找树没有键值相等的节点空树也是二叉查找树

那么,红黑树就是在二叉查找树的每个结点上增加一个存储位来表示节点的颜色,只能是红色或黑色,通过对任何一个节点着色方式的限制,红黑树确保没有一条路径比其它路径长出两倍。它有如下性质:

每个节点要么是红的,要么是黑的根节点是黑的每个叶子节点也是黑的如果一个节点是红色的,那么它的左右儿子节点是黑的对于任何一个节点,其到叶子节点的每条路径都包含相同数目的黑节点。

这样的特性保证了红黑树相对平衡,从而使得查找、删除、增加操作时间复杂度最坏为O(logn)。

当对红黑树进行插入删除操作时,会破坏树的结构,从而红黑性质也会破坏,通过对树的旋转和重新着色来调整。

STL中set和map容器都是采用红黑树的结构来维护的,具有自动调整树结构的特性。

这就是为什么set和map的插入删除操作效率比其他序列容器要高的原因,插入和删除的时候,只要变动对应指针指向即可,,并不需要做内存拷贝和内存移动;既然内存没有变化,那么相应的iterator也没有变化了,还是保存先前的值,所以在插入和删除操作之后,先前保存的iterator并不会失效

作者  | 2017-3-1 18:35:39 | 阅读(9) |评论(0) | 阅读全文>>

C++的反射

2016-12-29 21:07:35 阅读12 评论0 292016/12 Dec29

C++的反射:可以通过类的名字得到对应类型的对象

C++语言本身是不支持反射的,但实际应用中总是会有将对象序列化的需求,总不可能C++不支持,我们就不用C++了,既然发明C++的大师们没有考虑这个,那我们只有自己动手了,毛主席说过“自己动手,丰衣足食”!

天生限制

C++语言本身不支持反射机制,但C++对象总是要序列化的,序列化就是存储到磁盘上,将对象变成一定格式的二进制编码,然后要用的时候再将保存在磁盘上的二进制编码转化成一个内存中的对象,这个过程中总是需要有一个指示来告诉编译器要生成什么样的对象,最简单的方式当然就是类名了,例如:将一个ClassXXX对象存储到磁盘上,再从磁盘读取的时候让编译器根据“ClassXXX”名称来new一个对象。

但是问题出现了,C++语言本身不支持反射,也就是说不能通过如下方式生成一个对象:

ClassXXX object = new “ClassXXX”;

工厂方法

当然,这样的方法不行,那我们只有另辟蹊径。最简单的就是工厂方法了:

ClassXXX* object = FactoryCreate(“ClassXXX”);

至于FactoryCreate的设计就很简单了,if的集合就可以了:

if(name = “ClassXXX”)

return new ClassXXX;

作者  | 2016-12-29 21:07:35 | 阅读(12) |评论(0) | 阅读全文>>

class Base1

{

int m_i;

public:

Base1(int i) {m_i = i;}

virtual int sum() {return m_i;}//如果sum函数是非virtual函数,那么callfun(d)依旧调用的是Base1::sum,此时发生了类型向上转换;如果是virtual函数,那么根据多态原理,会调用派生类的sum函数

};

class Derived1 : public Base1

{

int m_j;

public:

Derived1(int i, int j) :Base1(i), m_j(j) {}

virtual int sum() {return Base1::sum() + m_j;}

};

void callfun(Base1 &b)//如果函数参数是非引用,会发生切片,那么callfun(d)依旧会调用Base1::sum

{

cout<<b.sum()<<endl;

作者  | 2016-12-29 21:05:09 | 阅读(12) |评论(0) | 阅读全文>>

一个解决方案内添加多个工程进行调试

2016-12-5 21:59:09 阅读11 评论0 52016/12 Dec5

像上节我说的管道程序,因为有server端程序和client程序,如果在编译器中打开多个解决方案会影响调试的速度,很是浪费时间,我收到有网友的提问,便把一个解决方案内添加多个工程文件进行调试的步骤说下。

拿命名管道的程序来说,首先建立server端的工程:

 这里我建立的是名为namedpipe解决方案,并且工程名字和方案名字一样,接下来:

点击【新建项目】

新建步骤和正常创建一样。这时,namedpipe解决方案下就有2个项目了:

编写好代码,编译,在此程序中,我们应该先启动server端程序,在namedpipe项目名称上,右键,选择【调试】->【启动新实例】

server端程序启动。接下来,在client项目名称上,右键,选择【调试】->【启动新实例】,那么2个程序就都启动了,可以直接进行调试了。

作者  | 2016-12-5 21:59:09 | 阅读(11) |评论(0) | 阅读全文>>

命名管道(Windows)

2016-12-2 18:41:42 阅读11 评论0 22016/12 Dec2

HANDLE CreateNamedPipe(

LPCTSTR lpName,                             /*管道名称*/

DWORD dwOpenMode,                        /*管道打开模式*/

DWORD dwPipeMode,                        /*管道的模式*/

DWORD nMaxInstances,                   /*管道能够创建的最多实例*/

DWORD nOutBufferSize,                 /*输出缓存大小*/

DWORD nInBufferSize,                    /*输入缓存大小*/

DWORD nDefaultTimeOut,                  /*管道的默认等待超时*/

LPSECURITY_ATTRIBUTES lpSecurityAttributes  /*安全属性*/

);

创建命名管道和打开已经存在的命名管道,其中lpName为管道名称,dwOpenMode为创建方式,可以是下面值的组合:

PIPE_ACCESS_INBOUND:管道只能用作接收数据。

PIPE_ACCESS_OUTBOUND:管道只能用作发送数据。

作者  | 2016-12-2 18:41:42 | 阅读(11) |评论(0) | 阅读全文>>

匿名管道(Windows)

2016-12-2 18:37:44 阅读10 评论0 22016/12 Dec2

BOOL CreatePipe(PHANDLE hReadPipe, // 指向读句柄的指针

 PHANDLE hWritePipe, // 指向写句柄的指针

 LPSECURITY_ATTRIBUTES lpPipeAttributes, // 指向安全属性的指针

 DWORD nSize // 管道大小);

管道(Pipe)实际是用于进程间通信的一段共享内存,创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后,另一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道,只能在本地计算机中使用,而不可用于网络间的通信。

管道服务器将lpPipeAttributes 指向的SECURITY_ATTRIBUTES数据结构的数据成员bInheritHandle设置为TRUE,那么CreatePipe()创建的管道读、写句柄将会被继承。lpPipeAttributes一般可以这么用:

SECURITY_ATTRIBUTES sa;

sa.bInheritHandle = TRUE;

sa.lpSecurityDescriptor = NULL;

sa.nLength = sizeof(SECURITY_ATTRIBUTES);

if (!CreatePipe(&hRead, &hWrite, &sa, 0))

作者  | 2016-12-2 18:37:44 | 阅读(10) |评论(0) | 阅读全文>>

巧用set容器

2016-11-20 8:58:04 阅读14 评论0 202016/11 Nov20

问题描述:目录下不确定有1.bmp 2.bmp 3.bmp.......的一个或多个,也不确定有没有,在不知道的情况下使得从1.bmp插入该目录中,比如,如果有2.bmp,再次插入的时候需要是1.bmp;如果有1.bmp,再次插入的时候是2.bmp

用set容器解决,可以遍历把所有的bmp保存在一个set中,然后循环插入set中1.bmp 2.bmp 3.bmp……,用pair保存插入的返回值,如果是true,则表示目录下不存在,如果是false,表示已存在,继续下一次循环:

set<CString> setFile;

pair< set<CString>::iterator, bool > setPair;

for (int i=1; i<nSize+2; i++)

{

CString csBmpName;

csBmpName.Format(_T("%d.bmp"), i);

setPair = setFile.insert(csBmpName);

if (setPair.second)

{

nRet = i;

break;

}

}

作者  | 2016-11-20 8:58:04 | 阅读(14) |评论(0) | 阅读全文>>

fstream读写bin文件

2016-9-1 20:56:42 阅读18 评论0 12016/09 Sept1

/*CData是一个存储数据的类*/

CData d;

ostream writeBin("data.bin");

writeBin.write(reinterpret_cast<char *>(&d), sizeof(d));

istream readBin("data.bin", ios::binary);

while(readBin.read(reinterpret_cast<char *>(&d), sizeof(d)))

{

cout<<d<<endl;

...

}

/*text文件的读写*/

ostream writeData("data.txt");

writeData<<d<<endl;

istream readData("data.txt");

cout<<readData.rdbuf();

可以看到text是直接把数据读到流中就可以了;bin二进制文件需要用write和read函数来读写了

作者  | 2016-9-1 20:56:42 | 阅读(18) |评论(0) | 阅读全文>>

a bug in xxx.exe or any of the dlls

2016-8-29 16:36:27 阅读20 评论0 292016/08 Aug29

取消登录按钮按过之后,本来以为是析构出问题了。

问题源头:

1、你的程序可能有能接收输入文字的部分,用到了输入法

2、搜狗输入法通过hook或驱动将自己的代码映射到了所有进程的地址空间,你的程序自然也要加载搜狗的代码。

看到没,上面的两个dll都是搜狗的dll,被程序加载了,然而这两个dll都不不是被正确的方式加载,所以出错。

作者  | 2016-8-29 16:36:27 | 阅读(20) |评论(0) | 阅读全文>>

查看所有日志>>

 
 
 
 
 
 我要留言
 
 
 
留言列表加载中...
 
 
 
 
 

发现好博客

 
 
列表加载中...
 
 
 
 
 
 
 
博友列表加载中...
 
 
 
 
 

天气

 
 
模块内容加载中...
 
 
 
 
 
 
 
列表加载中...
 
 
 
 
 
 
 
心情随笔列表加载中...
 
 
 
 
 

标签

 
 
数据加载中...
 
 
 
 
 
 
 

北京市 海淀区 摩羯座

 发消息  写留言

 
QQ826457306
博客等级加载中...
今日访问加载中...
总访问量加载中...
最后登录加载中...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017

注册 登录  
 加关注