博文
关于static成员变量(2007-09-03 10:00:00)
摘要:一直以为对static成员变量还算了解。直到昨晚看了《Effective C++》3rd Item49,才发现自己其实什么都不懂,真是惭愧!所以写下这篇随笔,为以后定期回顾参考,也希望大家不要犯类似的错误。
先看以下代码:
#include <iostream>
using namespace std;
class Base{
static int itest;
public:
void Set(){
itest++;
}
void Show(){
cout << itest << endl;
&nbs......
为数字加逗号分割(2007-08-30 15:22:00)
摘要:bruceteen的方法(使用一个如此设置的local):
#include <iostream>
#include <locale>
int main( void )
{
using namespace std;
cout << 1389992 << endl; // 1389992
locale chs( "chs" ); // chs在我这里行,不知道你那里怎么样
cout.imbue( chs );
cout << 1389992 << endl; // 1,389,992
}
特别推荐 namtso的方法(自己订制local):
#include <iostream>
#include <string>
#include <locale>
using namespace std;
class thousands_sep_facet:public std::numpunct<char>
{
public:
explicit thousands_sep_facet( size_t r=0 ) : std::numpunct<char>(r)
{
}
protected:
string do_grouping() const
{
return "\003";
}
};
int main( void )
{
cout << 1389992......
C++回调(CallBack)方案 (2007-08-17 12:03:00)
摘要:跟诸如Object Pascal和Ada等其它一些语言不同,C++语言并没有内在地提供一种将类的方法作为回调函数使用的方案。在C语言中,这种回调函数被称作算子(functor),在事件驱动类程序中普遍存在。主要问题基于这样一个事实:某个类的多个实例各自位于内存的不同位置。这就需要在回调的时候不仅需要一个函数指针,同时也需要一个指针指向某个实例本身(译者注:否则回调时便无法知道目前正在操作的是哪个对象,C++类的非静态方法包含一个默认的“参数”:this指针,就是起这种作用的)。所以,针对问题的定义,有一个很直观的解决方法就是使用模板和编译时的实例化及特化。
解决方案
这里的方案只支持一个模板参数,但如果一些能够如愿的话,随着更多的编译器完全实现C++标准,以后将会支持动态的模板参数,比如“…”形式的模板参数列表(参见《C++ Templates, The Complete Guide》),那时,我们就可以可以实现无需全部预定义的参数集合。(文中所有代码的注释为译者加,下同。)
template < class Class, typename ReturnType, typename Parameter >
class SingularCallBack
{
public:
//指向类成员函数的指针,用他来实现回调函数。
typedef ReturnType (Class::*Method)(Parameter);
//构造函数
SingularCallBack(Class* _class_instance, Method _method)
{
class_instance = _class_instance;
&nb......
c++ 重载决议与可访问性检查 (2007-08-07 09:23:00)
摘要:引用自:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1406781
对于如下的类:
class ClxECS
{
public:
double Test(double dValue) { return dValue * 13; };
private:
int Test(int iValue) { return iValue * 13; };
};
下面的函数输出是什么?
void ECS_test()
{
int iValue = 13;
ClxECS lx;
cout << lx.Test(iValue) << endl;
}
如果说你的答案是169,那么你就大错特错了!
因为上面的函数根本不能通过编译!编译器会给你一个不能访问私有成员的错误。
惊奇吗?难道编译器不能找到类ClxECS的公有成员函数double Test(double dValue)并把实参iValue类型转换为double吗?
答案是:不能!其实原因很简单:C++中重载决议是在可访问性检查之前进行的。
对于上面的例子,编译是按如下顺序进行的:
首先,编译器进行重载决议,去查找适合的成员函数(而不管查找到的成员函数是否为pu......
typedef的四个用途和两个陷阱(2007-06-21 11:30:00)
摘要:转自:赤龙的BLOG
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
// 和一个字符变量;
以下则可行:
typedef char* PCHAR; // 一般用大写
PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。
用途二:
用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
而在C++中,则可以直接写:结构名 对象名,即:
tagPOINT1 p1;
估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
有关 Windows Mobile 5.0 模拟器的网络配置(2007-03-17 11:23:00)
摘要:本文来自:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1190833
Step 1:配置面板-〉网络连接-〉右键点击Local Area Connection图标-〉属性。进入(图一)配置界面。
Step 2:如果已经存在红线标示的服务,则点击卸载,将其卸载掉。
Step 3:安装虚拟网卡驱动netsvwrap.msi,可以到MS的网站down一个。
Step 4:再次进入图一所示界面,会发现刚刚卸载的那个服务又出现了,这一次勾选该服务(即激活该服务),确定、退出。
Step 5:启动Visual Studio 2005,菜单选择:Tools-〉Options-〉Device Tools->Devices.在右侧的模拟器列表中选中要配置的模拟器,点击Properties按钮,进入模拟器配置界面。
Step 6:按下图所示配置。
Step 7:点击Emulator Options按钮。进入模拟器配置界面,点选NetWork标签。作如下配置:
Step 8:启动相应模拟器。配置模拟器:Start-〉Setting-〉Connections-〉Network Cards,进入(图 四)所示界面。
Step 9:将My network card connects to:置为 The Internet,并点击(图 四)红线所标示的选项。进入(图 五)界面。设置模拟器IP和网关以及DNS(下图只是举个例子,实际的设置需要你所处的网络环境来做,模拟器相当于和你的PC同处在一个网络内的机器)。确定。
Step 10:点击模拟器窗口菜单File-〉Configure->NetWork,若(图 七)红线标示选项未选中,则将其选中 OK;若该选项已经选中,则取消该选择,OK,并重新进入此界面将其选中,OK。
Step 11:Software Reset 模拟器。
Step 12:大功告成!......
time(2007-02-21 21:46:00)
摘要:你想知道你的代码究竟执行了多长时间吗?是的,有的时候我们需要确定我们的代码到底执行了多长时间。或许你会想这有何难,在代码的前后增加GetTickCount来得到时间不就可以了吗?没错,如果系统是线形执行的话,这样做肯定可以得到,但我们怎么能够保证系统是线形的来?
我们这里只讨论WINDOWS,WINDOWS是典型的多线程、抢占式的多任务操作系统。如果你的计算机只有一块CPU的话,那么你的应用程序是这样运行的:一个线程执行一个时间片,然后再由另外一个线程执行一个时间片(这个时间片是20毫秒),然后又可能暂停这个线程回到开始的哪个线程,也有可能执行其他的线程;这就是操作系统的调度算法了,调度算法是复杂的,目的是保证所有的线程都有机会被执行,从而看起来感觉每个线程都在运行,但实际上每个时刻只可能有一个线程在运行,即占用CPU时间(所以线程是分配CPU资源的最小单位了)。上面的是单CPU的,如果在多CPU上就更复杂了,但这个时候就不能保证一个时刻只有一个线程被执行了,因为可能在每个CPU上运行一个线程(WINDOWS2000就可以在多个CPU上运行),从而更好的保证了程序的并行性。
从我们对WINDOWS的分析可以看出,程序不是线性方式执行的。或许你会问:单线程、单CPU的情况下,程序是线性的吧?乍听起来说的有道理,但事实并不是这样,因为你的程序运行在操作系统上,操作系统要能够正确的运行,它本身就有许多线程在运行(EXPLORE.EXE),在必要的时候被唤醒,所以你的程序根本不可能在单线程的理想环境下运行。
好了,既然我们已经了解了上面的本质之后,你就会想,是的真的没有办法来得到我的代码到底执行了多长时间?其实不然,下面我们就几种测试方法来比较一下,究竟该如何计算?
用来计算代码执行时间有三种方法:
1. 使用GetTickCount,得到当前的时间,单位是毫秒
代码示例:
DWORD startTime = GetTickCount();
//被测试的代码
DWORD totalTime = GetTtickCount() – startTime;
2. 使用GetThreadTimes;该函数得到的时间包括两......
Class function callback(2007-01-26 10:20:00)
摘要:这篇文章介绍了如何使类中的非静态成员函数成为线程函数或者使其成为回调函数的方法,颇值得一读:
Introduction
In this article I'll show you how to make a callback to a function within a class that is NOT static. This will make use of functions, pointers and some assembly. It's not possible to my knowledge to do this without the ASM. However, this guide does not require you to know any ASM; instead it will explain what it does. This guide is not intended to teach out ASM, however. There's plenty of other good guides out there on the web for that. This is an advanced technique, however, but even beginners should be able to make use of it.
What do we need? A compiler that can do ASM and a class! In this article I will also show you how I used this technique to forward messages through a window proc. Let's get started then!
First then, we need a base-class. I use MFC in this sample to show you how this technique works. So if you want to follow in this sample, use MFC to create a dialog window. The class is the dialog class of your mai......
Use Pseudoregisters to debug in MSVC++(2006-12-24 23:49:00)
摘要:Introduction
Let's start with the reason why I wrote this article. One day, a colleague asked me to help him debug a problem he had. So I was watching him stepping in his code, when I noticed the following line: int test = GetLastError();
He did this, because he wanted to know the error code, if the previous function failed. He was adding this line every time he wanted to know the error code. I advised him to remove all those lines and use the @ERR pseudoregister in his watch window. He didn't know what it was and asking around in the office, a lot of other people didn't. So I came up with this article for people who have never heard of pseudoregisters.
What is a pseudoregister anyway?
A pseudoregister is not an actual hardware register, but is displayed as though it were a hardware register. With a pseudoregister, you can see and use certain values (error codes, thread information block...) in the debugger.
Let's have a look at the @ERR pseudoregister. Fire up your debugger wit......
谈谈连接器是如何工作的(2006-09-29 15:09:00)
摘要: 许多Visual C++的使用者都碰到过LNK2005:symbol already defined和LNK1169:one or more multiply defined symbols found这样的链接错误,而且通常是在使用第三方库时遇到的。对于这个问题,有的朋友可能不知其然,而有的朋友可能知其然却不知其所以然,那么本文就试图为大家彻底解开关于它的种种疑惑。
大家都知道,从C/C++源程序到可执行文件要经历两个阶段:(1)编译器将源文件编译成汇编代码,然后由汇编器(assembler)翻译成机器指令(再加上其它相关信息)后输出到一个个目标文件(object file,VC的编译器编译出的目标文件默认的后缀名是.obj)中;(2)链接器(linker)将一个个的目标文件(或许还会有若干程序库)链接在一起生成一个完整的可执行文件。
编译器编译源文件时会把源文件的全局符号(global symbol)分成强(strong)和弱(weak)两类传给汇编器,而随后汇编器则将强弱信息编码并保存在目标文件的符号表中。那么何谓强弱呢?编译器认为函数与初始化了的全局变量都是强符号,而未初始化的全局变量则成了弱符号。比如有这么个源文件:
extern int errorno;
int buf[2] = {1,2};
int *p;
int main()
{
return 0;
}
其中main、buf是强符号,p是弱符号,而errorno则非强非弱,因为它只是个外部变量的使用声明。
有了强弱符号的概念,链接器(Unix平台)就会按如下规则(参考[1],p549~p550)处理与选择被多次定义的全局符号:
规则1: 不允许强符号被多次定义(即不同的目标文件中不能有同名的强符号);
规则2: 如果一个符号在某个目标文件中是强符号,在其它文件中都是弱符号,那么选择强符号;
规则3: 如果一个符号在所有目标文件中都是弱符号,那么选择其中任意一个;
虽然上述3条针对的是Unix平台的链接器,但据作者试验,至少VC6.0的linker也......