记录学习过程中的点点滴滴
c++

C++插件机制的一种实现方法(对象工厂)
七 21st
背景
在我们的实际开发过程中,经常会开发一些插件,比较常见的例子如:给你 DataHandler,它是一个抽象类,提供一些数据操作的接口,然后插件开发者就需要继承DataHandler,并按需求实现对应的接口,将其作为插件,编译到最终的二进制程序中,最后通过配置文件指定生效该插件。
// data_handler.h Class DataHandler { public: virtual bool Handle(std::vector<Data*> data_list) =0; virtual ~DataHandler(){} }; REGISTER_REGISTER(DataHandler) #define REGISTER_DATA_HANDLER(name) REGISTER_CLASS(DataHandler, name)
// my_data_handler.h class MyDataHandler : public DataHandler { public: virtual bool Handle(std::vector<Data*> result_list); };
// my_data_handler.cc bool MyDataHandler::Handle(std::vector<Data*> data_list) { // Implemention... } REGISTER_DATA_HANDLER(MyDataHandler)
// configure file DataHandler{ name : MyDataHanlder, prior : 1 } DataHanlder{ name : YourDataHandler, prior : 1 }
此时你只需把你的MyDataHandler编译为动态库或者是静态库,并链接到最终二进制中,在数据处理时就会调用你的DataHandler。是不是很方便开发哈,这就是所谓的插件开发思想。下面主要介绍下具体的实现。
实现思想
想要实现上述功能的插件框架,主要从以下几个方面着手解决:
1. 如何组织不同类型的插件,如目前有DataHanlder,但是系统可能也支持ServiceHanlder等等;某类插件可能包含多个具体的实例的插 件,那又如何组织;这里很容易就想到了双层map的数据结构,如下图所示,每层Map的Key都插件类型或者具体插件名字,value为对应的工厂对象, 工厂对象生成对应的实例,具体如下图所示:
2. 如何生成对象工厂类呢? 这里首先不能将这个工作交给插件开发者,一方面开发量增大,另一方面也暴漏系统实现细节;但是也不能框架开发者手工实现,因为框架本身无法预知都有哪些插件需要开发。
所以可能的方法包括模板函数或者是宏定义了,本文使用宏定义进行实现,包括插件类型工厂和某个插件工厂。
scoped_ptr,shared_ptr和weak_ptr用法和实现方法
七 14th
scoped_ptr, shared_ptr和weak_ptr的都称为智能指针,但是各个的用法都不太一样,
本文就就详细介绍其具体用法以及具体实现方法。
-
用法介绍
- scoped_ptr: “scoped”即作用域的含义,主要用于指针在某个作用域中有效,当离开作用域时,该指针自动释放,这就避免了出现忘记回收内存的情形,同时scoped_ptr的复制构造函数和赋值函数为私有,这样就避免了指针的传递, 示例如下:
- shared_ptr: 共享所有权的智能指针,当某个对象需要在多个地方使用时,被多个指针引用,此时程序可能就无法确定在何时释放该对象,因此就需要使用“引用计数”的方法,当对象被引用的次数为0时,自动释放该对象,示例代码如下:
- weak_ptr: shared_ptr是强引用,而weak_ptr是弱引用;当使用shared_ptr出现循环引用时,造成内存无法释放,如果 你能预料到此种情况发生,你就应该使用weak_ptr类型;另外weak_ptr不会增加所指对象的引用计数,但是会增加计数器的对象引用计数,这点可以后面的实现中看到这点,详细请点击这里
scoped<T> g_ptr; { scoped_ptr<T> ptr(new T); g_ptr = ptr;//illegal, because the assign operator is private. //T* will deleted when it goes out of this scoped. }
shared_ptr<T> g_ptr; { shared_ptr<T> ptr<new T>; // reference count is 1. g_ptr = ptr; //now reference count is 2 // when it goes out of this scoped, the reference count is 1 } //the reference count is 1. g_ptr->foo();
-
实现原理
- scoped_ptr的实现:其主要是在其析构函数中delete对象,同时将copy constructure 和 assign operator设置为私有,避免了指针的传递,这点比auto_ptr安全的多;另外scoped_array是针对new[]和delete[]的只能指针,具体实现请见附件。
- shared_ptr的实现:其主要用到了引用计数,每个指向同一对象shared_ptr都指向同一个计数器,其中计数器的定义如下,当shared_ptr对象复制时,对象引用计数加1,当shared_ptr对象释放时,引用计数减1,当引用计数减为0时,delete所指的对象。具体实现请看附件。
- weak_ptr的实现:需要注意的一点weak_ptr需要使用shared_ptr构造,不能直接使用原始指针进行构造,它主要操作的是weak_count_计数器,具体实现请看附件。
// This class is an internal implementation detail for shared_ptr. class SharedPtrControlBlock { template <typename T> friend class shared_ptr; template <typename T> friend class weak_ptr; private: SharedPtrControlBlock() : refcount_(1), weak_count_(1) { } int refcount_; //对象的引用计数 int weak_count_; //weak_ptr的引用计数 };
模板成员函数为什么不能是虚函数
三 4th
这个问题疑惑好久了,去年找工作时,面试网易游戏就被问到这个问题,没有搞清楚,今天看STL源码分析时,突然想到了,就上网查了,算是把这个问题搞明白了
解释
当前的编译器都期望在处理类的定义的时候就能确定这个类的虚函数表的大小,如果允许有类的虚成员模板函数,那么就必须要求编译器提前知道程序中所有对该类的该虚成员模板函数的调用,而这是不可行的
为什么作者这样说呢?从上面的演示知道,对于一个模板函数,不同的模板参数会产生出不同的函数。这样的话,如果要知道类内包含多少个虚函数,就只能去代码中寻找。这就不单单是多文件的问题,还有RTTI的问题了。
主要是参考了http://blog.csdn.net/jcwkyl/article/details/3771059文章,原来是还是吉大的师兄呢,呵呵

C++ Web编程
四 7th
C++ Web编程
译者 yaronli (http://www.yaronspace.cn/blog)
原文地址:http://www.tutorialspoint.com/cplusplus/cpp_web_programming.htm
什么是CGI
CGI( Common Gateway Interface ),公共网关接口是一组标准,该标准定义了在 web server和普通脚本间是如何交换信息的。
Web浏览 (Web browsing)
为了更好的理解CGI的概念,我们看看当用户为了访问某个页面或者url点击链接时所发生的事情:
- 你的浏览器联系到HTTP 服务器,然后请求对应的URL,即对应的文件;
- Web服务器会解析这个URL,然后查找对应文件名。如果找到这个文件,Web服务器就会返回文件的内容给浏览器,否则 的话会返回一条错误信息;
- Web 浏览器从Web服务器获得响应信息,然后解析返回的文件内容或者是错误信息;
但是,可以这样设置HTTP服务器,当一个文件被请求时,不是将文件内容返回,而是将它作为程序来执行,并将程序产生的输出返回给你的浏览器来显示。
公共网关接口(CGI)就是这样一种协议,它使应用程序(叫做CGI程序或者是CGI脚本)能够与Web服务器交互。CGI程序可以使用Python、perl、Shell、C或者C++来编写。
CGI的架构图
下图展现了CGI的简单架构:
Web服务器的配置
在你处理CGI程序之前,请确定你的Web服务器支持CGI程序并且它配置为支持能够处理CGI程序。所有的被HTTP服务器执行CGI程序都会预先配置在规定的目录,这个目录传统上被命名为/var/www/cgi-bin/,默认情况下cgi程序的扩展名为.cgi,尽管它们是C++可执行文件。
C中宏使用小贴士与小技巧[原创]
四 1st
C中宏使用小贴士与小技巧
译者 yaronli(http://www.yaronspace.cn/blog)
英文地址:http://www.mikeash.com/pyblog/friday-qa-2010-12-31-c-macro-tips-and-tricks.html
预处理 VS 编译
为了理解C中的宏,首先需要理解一个C程序是怎么编译的。特别的,你必须知道在预处理阶段和编译阶段发生的事情的不同之处。
就像名字所说的,预处理首先执行。它会做一些简单的文本操作,比如:
- 去除注释
- 处理#include 指令,用include文件内容对它们进行替换
- 判断#if 和 #ifdef指令
- 评估#define指令
- 根据已经定义#define指令,扩展哪些在剩余代码中找到的宏
显然,最后两条与今天讨论的内容最相关。
可以看到,预处理器对它所处理的文本内容并不关心。对于这点也有例外,比如,它知道这是个字符串,并不会扩展里面的的宏:
#define SOMETHING hello char *str = "SOMETHING, world!" // nope
同时它也可以计算括号的数目,所以它知道这个逗号不会传递给宏两个参数:
#define ONEARG(x) NSLog x ONEARG((@"hello, %@", @"world"));
但是通常来说,预处理器对它所处理的内容并不了解。例如,你不能使用#if来判断一个类型是否已经定义:
// makes no sense #ifndef MyInteger typedef int MyInteger #endif
即使MyInteger类型已经定义,#ifndef也会返回true,类型定义发现在编译阶段,此时还未发生。
同样的,对于#define定义的内容也不需要是语法正确的。下面的定义是完全合法的,尽管这是定义宏的很不好的方式:
#define STARTLOG NSLog( #define ENDLOG , "testing"); STARTLOG "just %" ENDLOG
预处理只是盲目地用它们定义的内容来替换STARTLOG和ENDLOG。到时编译器会使此段代码有意义,而且它确实是有意义的,完全可以编译成为有效地代码。 更多 >
C++中extern “c”深层含义
二 22nd
extern “C” 代表双重含义:从字面意思上看,一被修饰的目标是extern,二被修饰的目标是C。
1,首先被extern “C”限定的函数或变量是extern类型的,
extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
2,被extern “C”修饰的变量和函数是按照C语言方式编译和连接的;
也就是说C和C++对于编译器来说编译的方式是不同的,作为面向对象程序语言,C++支持函数重载,而C语言不支持函数重载,即某个函数被C++编译器编译后和被C编译器编译后的名字是不同的。例如,函数的原型为:
void foo(int, int);
假如C++编译后的名字为:_foo_int_int
C编译后的名字为:_foo_
如果在C++中使用C语言提供的库函数时,在引用完头文件后,在链接时,可以无法再目标代码中找到_foo_int_int类似的函数,只能找到_foo_函数,所以会出现函数未定义的错误。
总的来说一句话:extern “C”的存在时为了C和C++能够进行混合编程。
关于extern “C” 的用途,请参看我的另一篇文章
C语言调用C++库接口的方法概述
参考资料:
http://www.cppblog.com/Macaulish/archive/2008/06/17/53689.html
计算器实现方法
九 25th
实现计算器有两种常用的方法:
1,转化为逆波兰表达式,然后对逆波兰表达式进行计算,比较常用,C语言教材中的标准方法
http://en.wikipedia.org/wiki/Shunting-yard_algorithm
2,利用编译原来中的词法分析和递归下降的语法分析方法,扩展性比较好
有时间实现下~~
如何写出优美的 C 代码[zz]
九 3rd
面向对象的语言更接近人的思维方式,而且在很大程度上降低了代码的复杂性,同时提高了代码的可读性和可维护性,传统的 C 代码同样可以设计出比较易读,易维护,复杂度较低的优美代码,本文将通过一个实际的例子来说明这一点。
除了提供基本数据类型外,C 语言还提供给用户自己定制数据类型的能力,那就是结构体,在 C 语言中,你可以用结构体来表示任何实体。结构体正是面向对象语言中的类的概念的雏形,比如:
typedef struct{ float x; float y; }Point; |
定义了一个平面坐标系中的一个点,点中有两个域,x 坐标和 y 坐标。
结构体中的域称为结构体的成员。结构体中的数据类型可以是简单数据类型,也可以是其他的结构体,甚至结构体本身还可以嵌套,比如,一个标准的链表结构可以进行如下定义:
typedef struct node{ void *data;// 数据指针 int dataLength;// 数据长度 struct node *next;// 指向下一个节点 }Node; |
可以看到,结构体 node 中的 next 指针的类型又是 node 类型。
指针是 C 语言的灵魂,是 C 比其他语言更灵活,更强大的地方。所以学习 C 语言必须很好的掌握指针。函数指针,即指向函数在内存映射中的首地址的指针,通过函数指针,可以将函数作为参数传递给另一个函数,并在适当的时候调用,从而实现异步通信等功能。
比如, UNIX/Linux 系统中的信号注册函数,其原型如下:
void (*signal(int signo,void (*func)(int))) (int) |
使用的时候,需要自己在外部定义一个信号处理函数 (signal handler), 然后使用 signal(sigNo, handler) 将处理程序注册在进程上,当信号发生时,进程就可以回调信号处理函数。
正如前面提到的,结构体的成员可以是简单的数据结构,也可以是其他的结构体,当然,也可以是指针。当将函数指针作为结构体的成员,并且这些函数只用来操作本结构体中的数据时,就可以形成一个独立的实体,这个实体中既有数据,也有对数据的操作,这样自然就可以引出类(class)
的概念。
原文地址:http://www.ibm.com/developerworks/cn/linux/l-cn-cobject/index.html?ca=drs-cn-0925
c++ md5函数的实现
八 24th
今天从网上找到了,记录下~
main.cpp
#include <iostream> #include "md5.h" using namespace std; int main(int argc, char *argv[]) { cout < < "md5 of 'grape': " << md5("grape")<<endl; return 0; }
c++中的浮点运算问题
十一 24th
从topLanguage看到的:http://groups.google.com/group/pongba/browse_thread/thread/9361e17333282db8?hl=zh-CN
很有意思的 更多 >
近期评论