问:
在构造或析构期间能使用虚函数吗?
答:
能,但最好不要这么做。
前两天在公司游戏项目开发过程中,在析构函数中不小心调用了虚函数,而且还是个纯虚函数。
因为一直是在Rlease模式下工作的,导致系统直接终止客户端,虽然控制台有打印这个错误,但终止太快,也没看到。切换在Debug下调试,则会报R6025 -pure virtual function call 的运行时错误。
当然,如果在析构函数中直接调用纯虚函数,编译器也不傻(VS2008),它不会让编译通过的,因为纯虚函数没有实现体,所以会出现unresolved external symbol链接错误。但是通过其他函数间接调用,编译器就不会发现,就会出错。
直接看下面这个例子吧
class TestEffect
{
public:
TestEffect(){}
~TestEffect(){ release(); }
void release(){ clear(); }
virtual void clear() = 0;
};
class SubTestEffect: public TestEffect
{
public:
SubTestEffect(){}
~SubTestEffect(){}
virtual void clear(){ printf( "SubTestEffect::clear() called\n" }
};
这样new出来一个SubTestEffect的实例,在delet ......
问:
在构造或析构期间能使用虚函数吗?
答:
能,但最好不要这么做。
前两天在公司游戏项目开发过程中,在析构函数中不小心调用了虚函数,而且还是个纯虚函数。
因为一直是在Rlease模式下工作的,导致系统直接终止客户端,虽然控制台有打印这个错误,但终止太快,也没看到。切换在Debug下调试,则会报R6025 -pure virtual function call 的运行时错误。
当然,如果在析构函数中直接调用纯虚函数,编译器也不傻(VS2008),它不会让编译通过的,因为纯虚函数没有实现体,所以会出现unresolved external symbol链接错误。但是通过其他函数间接调用,编译器就不会发现,就会出错。
直接看下面这个例子吧
class TestEffect
{
public:
TestEffect(){}
~TestEffect(){ release(); }
void release(){ clear(); }
virtual void clear() = 0;
};
class SubTestEffect: public TestEffect
{
public:
SubTestEffect(){}
~SubTestEffect(){}
virtual void clear(){ printf( "SubTestEffect::clear() called\n" }
};
这样new出来一个SubTestEffect的实例,在delet ......
curl c api
关于Curl的介绍很多,这里不详细介绍,主要谈一下简单应用。
最近研究了一下Linux下的curl C API,curl c API的文档比较丰富,唯一就是查找起来,费些时间。Curl的C API和curl的PHP API,函数接口和作用大致相同,所以如果有PHP API使用经验应该很好理解。
1:CURLcode curl_global_init(long flags);函数,这个函数全局需要调用一次(多次调用也可以,不过没有必要), 所以这也是把Curlplus设计成单体类的原因,curl_global_init函数在其他libcurl函数调用前至少调用一次,程序最后需要调用curl_global_cleanup,进行清理。
参数:flags
CURL_GLOBAL_ALL Initialize everything possible. This sets all known bits.
CURL_GLOBAL_SSL Initialize SSL
CURL_GLOBAL_WIN32 Initialize the Win32 socket libraries.
CURL_GLOBAL_NOTHING Initialise nothing extra. This sets no bit.
CURLcode 是一个enum,当CURLcode为CURLE_OK时,表示函数执行成功,否则失败,具体错误原因可以查看<curl/curl.h>文件内的定义。
2:curl_easy_init - Start a libcurl easy session
curl_easy_init用来初始化一个CURL的指针(有些像返回FILE类型的指针一 ......
va系列宏的用法的一般步骤:
vsptr(char *format, ...) //切记此处的格式
{
va_list argptr;
va_start(argptr, format); //使得argptr指向以format开头的存储空间
va_arg(argptr, type); //取传递的参数
...
va_end(argptr); //结束,释放argptr所占用的内存空间
}
判断argptr所指向的参数是否已经取完了的方法:1-可以传递的个数 2-采用vsprintf/vsnprintf系列的函数(可以将所有的参数一次去完),该函数的常用用法如下示例:
#include<stdio.h>
#include <stdarg.h>
#define bufsize 80
char buffer[bufsize];
int vspf(char *fmt, ...)
{
va_list argptr;
int cnt;
va_start(argptr, fmt);
cnt = vsnprintf(buffer,bufsize ,fmt, argptr);
va_end(argptr);
return(cnt);
}
int main(void)
{
int inumber = 30;
float fnumber = 90.0;
char string[4] = "abc";
vspf("%d ......
(转)C++中extern “C”含义深层探索
1.引言
C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。
2.从标准头文件说起
某企业曾经给出如下的一道面试题:
面试题
为什么标准头文件都有类似以下的结构?
#ifndef __INCvxWorksh
#define __INCvxWorksh
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* __INCvxWorksh */
分析
显然,头文件中的编译宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif” 的作用是防止该头文件被重复引用。
那么
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
的作用又是什么呢?我们将在下文一一道来。
& ......
(转)C++中extern “C”含义深层探索
1.引言
C++语言的创建初衷是“a better C”,但是这并不意味着C++中类似C语言的全局变量和函数所采用的编译和连接方式与C语言完全相同。作为一种欲与C兼容的语言,C++保留了一部分过程式语言的特点(被世人称为“不彻底地面向对象”),因而它可以定义不属于任何类的全局变量和函数。但是,C++毕竟是一种面向对象的程序设计语言,为了支持函数的重载,C++对全局函数的处理方式与C有明显的不同。
2.从标准头文件说起
某企业曾经给出如下的一道面试题:
面试题
为什么标准头文件都有类似以下的结构?
#ifndef __INCvxWorksh
#define __INCvxWorksh
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* __INCvxWorksh */
分析
显然,头文件中的编译宏“#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif” 的作用是防止该头文件被重复引用。
那么
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
的作用又是什么呢?我们将在下文一一道来。
& ......
内容:Introduction 和 Error Reporting
1. glibc 所实现全部或部分规范下的功能有
ISO C: The international standard for the C programming language.
POSIX: The ISO/IEC 9945 (aka IEEE 1003) standards for operating systems.
Berkeley Unix: BSD and SunOS.
SVID: The System V Interface Description.
XPG: The X/Open Portability Guide.
如果只需要 ISO C 的功能,能在编译时使用 -ansi 选项。glibc 实现了全部的 ISO C 功能。POSIX 是 ISO C 的超集,他额外的包括了 file system interface primitives、device-specific terminal control functions、process control functions。Berkeley Unix 实现了前两者多数功能,源于 4.2 BSD、4.3 BSD, and 4.4 BSD Unix 系统(一般称为 Berkeley Unix)及 SunOS (基于 4.2 BSD 不过又实现了 System V 的部分功能),他额外的包括了 symbolic links、the select function、BSD signal functions、sockets。SVID 是 System V Interface Description,也就是描述 AT&T Unix System V operating system 的一份文件,某种意义上是 POSIX 的超集,不过没有已有的 Unix 实现了其全部功能,glibc 也仅仅实现了其部 ......
内容:Memory
1. 几个基本概念,page、frame、paging、segment。
进程分配内存的两种模式,一个使用 exec 系列函数,一个使用 programmatically(malloc 等函数)。
重要的 segment 有 text segment(存放代码等等,一般在进程的生命周期中不变)、data segment
(存放数据,能用一些函数来调整大小,不过低位端位置不变)、stack segment(随着使用的堆栈
变大而变大,但不变小...)
2. 内存的静态分配和自动分配。前者是对于 static 变量或全局变量,一旦开始就分配,即一直存在到最后。
后者是临时变量,如调用函数。值得注意的是:
In GNU C, the size of the automatic storage can be an expression that
varies. In other C implementations, it must be a constant.
3. 内存的动态分配不为 C 语言本身支持,不像 C++。基本方法是
void * malloc (size_t size)
分配到的内存没有初始化(calloc 会做清零,clear allocate),因此能用 memset 来
进行初始化。分配后应检测返回指针是否为 NULL。malloc 返回的一个块多数情况下对齐
(这样能存储任意类型的数据)过了,地址为 8 的倍数(64 位系统里面是 16 的倍数),
在一些特别情况下(page 的边界)能 ......