工作到了今天,看到了很多,也想到了很多,其实感觉自己一路走来还是不容易。刚工作的时候的心态还是很稚嫩,其实一直到今天自己还是在不停地摸索,怎么去完善自己的情商。其实我一直觉得,知识,尤其是工作上的知识,要掌握下来是不难的。我觉得更难得是怎么去让自己的思考方式比别人更加好,这更是一条更难跨越的沟壑。无论什么知识,其实你能掌握的,别人比你花个多两倍,三倍的时间,总也能掌握到得,但是一个人比别人的“能力”显得更强,更多的是这个人在一个领域,一个问题上是否能思考得更加深入,能够更多地从多个方面去切入问题的核心来思考。
到了今时今日,我当然深知自己的知识体系还是有很大的不足,相对于很多ACM牛人,我的解题能力不足,相对于在此领域探索很多年的人,我的经验,我的思考方式还是有很大的不足。怎么能够从各个方面发挥自己的能力,能更好地进步呢?这应该是成为我以后几年一直思考的问题。
回想自己的职业之路,只工作了一年便跳槽显然并不是最好的选择,另外跳的对象也并不是一个很好的平台。虽然自己一直认为自己一定会走上创业这条路,但是现在自己却越来越觉得还是更喜欢和技术打交道,还是希望自己能在一个很好的平台上去做自己喜欢的事情,现在,显然我还没找到这样一个平台。
2009年5月1日星期五
InnoDB和MyISAM的差别[zz]
InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
MyIASM是IASM表的新版本,有如下扩展:
二进制层次的可移植性。
NULL列索引。
对变长行比ISAM表有更少的碎片。
支持大文件。
更好的索引压缩。
更好的键码统计分布。
更好和更快的auto_increment处理。
以下是一些细节和具体实现的差别:
1.InnoDB不支持FULLTEXT类型的索引。
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”
任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。
MyIASM是IASM表的新版本,有如下扩展:
二进制层次的可移植性。
NULL列索引。
对变长行比ISAM表有更少的碎片。
支持大文件。
更好的索引压缩。
更好的键码统计分布。
更好和更快的auto_increment处理。
以下是一些细节和具体实现的差别:
1.InnoDB不支持FULLTEXT类型的索引。
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含 where条件时,两种表的操作是一样的。
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。
4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。
5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。
另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”
任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。
2009年2月18日星期三
[zt]C++中的typename关键字(想哪儿说哪儿)
可能是C++的设计者(BJ?)觉得没用必要引入更多的关键字,其实模板刚刚引入C++中的时候并没有typename关键字。那时候定义类模板的类型参数通常使用class关键字。如:
template
class Test
{
public :
T t;
.....
};
随着模板应用的推广,大家发现使用typedef非常关键,因为实例化后的模板定义通常很长,通过使用typedef可以有效的缩短代码长度。如:
class UseTest
{
public:
typedef Test intTT;
...
};
这时问题就来了,当我写UseTest::intTT,这个intTT究竟是UseTest的一个静态成员(static)还是一个类型呢?所以typename关键字就引入了C++。
所以在定义一个intTT的对象时,我们就要这样写:
typename UseTest::intTT int_tt_obj;
通过typename明确指出intTT是一个类型而不是一个静态成员。
C++中的typename关键字(想哪儿说哪儿)
template
class Test
{
public :
T t;
.....
};
随着模板应用的推广,大家发现使用typedef非常关键,因为实例化后的模板定义通常很长,通过使用typedef可以有效的缩短代码长度。如:
class UseTest
{
public:
typedef Test
...
};
这时问题就来了,当我写UseTest::intTT,这个intTT究竟是UseTest的一个静态成员(static)还是一个类型呢?所以typename关键字就引入了C++。
所以在定义一个intTT的对象时,我们就要这样写:
typename UseTest::intTT int_tt_obj;
通过typename明确指出intTT是一个类型而不是一个静态成员。
C++中的typename关键字(想哪儿说哪儿)
2009年1月19日星期一
python Unicode I/O
在系统内部, Unicode 字符串被表示为一个16位整数序列,8-bit 字符串则是一个字节序列, 绝大多数字符串操作被扩展为能够处理更宽范围的字符值。只要 Unicode 字符串被转换为字节流,就必然会产生一系列问题(需要解决)。首先,要考虑现有软件的兼容性, 对那些仅支持 ASCII或其它 8-bit的软件来说,将 Unicode字符串转化为 ASCII字符串是较好的方法。其次, 16-bit 字符占用两个字节,字节顺序问题虽然比较无聊但必须考虑。对一个Unicode字符 U+HHLL 来说, 小端法编码方案将低位字节放在前面, 即 LL HH;大端法编码方案则将高位字节放在前面,即 HH LL. 就因为这么点问题, 不指定编码方案,你就无法将原始 Unicode 数据写入文件.
要解决这些问题, 只能根据特定的编码规则将 Unicode 字符串进行客观表示。这些规则定义了如何将 Unicode 字符表示为字节序列。在第四章, 针对 unicode()及 s.encode() 首先介绍了编码规则。举例来说:
Toggle line numbersToggle line numbers
1 a = u"M\u00fcller"
2 b = "Hello World"
3 c = a.encode('utf-8') # Convert a to a UTF-8 string
4 d = unicode(b) # Convert b to a Unicode string
codecs 模块用类似的技术解决了 Unicode 的输入输出问题。 codecs 模块拥有一系列转换函数依据不同的编码方案完成字节数据和 Unicode 字符串的转换。通过调用 codecs.lookup(encoding) 函数来选择一种编码方案。这个函数返回一个包括四个元素的 tuple (enc_func, decode_func, stream_reader, stream_writer ). 举例来说:
Toggle line numbersToggle line numbers
1 import codecs
2 (utf8_encode, utf8_decode, utf8_reader, utf8_writer) = \
3 codecs.lookup('utf-8')
enc_func (u [,errors ]) 函数接受一个 Unicode 字符串 u ,返回值是tuple(s , len).其中 s 是转码后的 8-bit 字符串(内容为 u 的一部分或全部), len 是被成功转换的 Unicode 字符数. decode_func(s [,errors]) 函数接受一个 8-bit 字符串,返回值是 tuple(u, len)。其中 u 是一个 Unicode字符串(内容为 s 的一部分或全部),len 是被成功转换的字符数。errors 决定转化过程中的错误如何处理,它的值可能是 'strict' 或 'ignore' 或 'replace'。若是 'strict'模式, 编码错误将引发 UnicodeError 异常。 若是 'ignore' 模式, 编码错误将被忽略。若是 'replace' 模式,无法转换的编码将被替换为 '?' 字符(Unicode字符U+FFFD或8-bit字符 '?')。
stream_reader 用来对文件对象进行封装,以支持 Unicode 数据读取. 调用 stream_reader (file) 返回封装后的文件对象,它的 read(), readline(), 及 readlines() 方法支持读取 Unicode 字符串数据. stream_writer 用来对文件对象进行封装,以支持将 Unicode 字符串写入文件。调用 stream_writer(file) 返回封装后的文件对象,它的 write() 和 writelines() 方法将 Unicode 字符串按给定的编码转换为字节流写入文件中。
下面的例子演示了如何使用这些方法处理 UTF-8 编码的 Unicode 数据:
Toggle line numbersToggle line numbers
1 # 输出 Unicode 数据到文件
2 ustr = u'M\u00fcller' # 一个Unicode 字符串
3
4 outf = utf8_writer(open('foo','w')) # 创建 UTF-8 字节流
5 outf.write(ustr)
6 outf.close()
7
8 # 从一个文件读取 unicode 数据
9 infile = utf8_reader(open('bar'))
10 ustr = infile.read()
11 infile.close()
当处理 Unicode文件时, 数据编码通常内嵌在文件本身当中。举例来说,XML 解析器根据文件的前几个字节'' 来判断文件编码. 如果最初的四个值是 3C 3F 78 6D ('
用类似下面的代码来读取文档的编码:
Toggle line numbersToggle line numbers
1 f = open("somefile")
2 # Determine encoding
3 ...
4 (encoder,decoder,reader,writer) = codecs.lookup(encoding)
5 f = reader(f) # Wrap file with Unicode reader
6 data = f.read() # Read Unicode data
7 f.close()
1.6.1. Unicode 数据编码
表 9.2 列出了codecs模块中目前正在使用的所有编码
表 9.2. codecs 模块中的全部编码器
编码 描述
'ascii' ASCII 编码
'latin-1', 'iso-8859-1' Latin-1 或 ISO-8859-1 编码
'utf-8' 8-bit 变长编码
'utf-16' 16-bit 变长编码
'utf-16-le' UTF-16, 显式小端编码方案
'utf-16-be' UTF-16, 显式大端编码方案
'unicode-escape' 和 u"string " 格式相同
'raw-unicode-escape' 和 ur"string "格式相同
下面的段落描述了各种编码的细节:
'ascii' 编码:
'ascii' 编码, 字符值的范围被限制在[0,0x7f] 和 [U+0000, U+007F]。超出这个范围的任何字符都是非法的。
'iso-8859-1' 或 'latin-1' 编码:
字符可以是任意的 8-bit 值([0,0xff] 及 [U+0000, U+00FF]). 取值范围 [0,0x7f] 内的字符对应 ASCII 字符集,取值范围 [0x80,0xff] 内的字符对应 ISO-8859-1 或 扩展 ASCII 字符集。超出 [0,0xff] 取值范围的任何字符都会造成错误。
'utf-8' 编码:
UTF-8 是一种变长编码,它能表示所有的Unicode字符。一个单独的字节用来表示值为 0–127 的 ASCII 字符。所有其它字符均被表示为多字节序列(双字节或3字节)。这些字节的编码见下表
Unicode 字符 Byte 0 Byte 1 Byte 2
U+0000 - U+007F 0nnnnnnn
U+007F - U+07FF 110nnnnn 10nnnnnn
U+0800 - U+FFFF 1110nnnn 10nnnnnn 10nnnnnn
对两字节序列, 第一个字节的前三个比特总是 110. 对三字节序列, 第一个字节的前三个比特总是 1110. 多字节序列的所有后来字节的前两个比特都是 10。
UTF-8 格式一个字符最多可以使用六个字节。 Python 中, 四字节 UTF-8 序列被称为代理对,用来对一对 Unicode 字符进行编码。这一对字符的取值都在[U+D800, U+DFFF]范围内并组合成一个 20-bit 的值. 代理对这样编码:四字节序列 111100nn 10nnnnnn 10nnmmmm 10mmmmmm 被编码成这样一对: U+D800 + N , U+DC00 + M , 其中 N 是高10位, M 是低十位。五字节和六字节 UTF-8 序列(开始位分别为 111110 和 1111110) 用来对32比特值的Unicode字符进行编码。Python目前不支持五字节和六字节UTF-8序列。如果数据流中存在这样的数据会引发 UnicodeError 异常。
UTF-8 编码对旧程序支持的相当好. 首先,标准 ASCII 字符的编码没有发生任何改变。这意味着 UTF-8 编码的 ASCII 字符串与传统的 ASCII 字符串完全相同。其次, UTF-8 编码的多字节序列未内嵌 null 字节。这样现有的基于 C 库的软件和程序所使用的 null-结尾的 8-bit 字符串可以与 UTF-8 字符串相容. 最后,UTF-8 编码 保留了字符串的字典顺序。也就是说如果 a 和 b 是 Unicode 字符串并且 a < b, 则当 a 和 b被转化为UTF-8编码后, a < b 仍然成立。因此,写给 ASCII 字符串的排序算法及其它与顺序有关的算法也一样可以工作在 UTF-8 编码上。
'utf-16' , 'utf-16-be' , and 'utf-16-le' 编码:
UTF-16 是一种变长16位编码,其中 Unicode 被记录为 16-bit 值。如果未指定字节顺序,则默认为大端法编码方案。另外,一个特殊的字符 U+FEFF 可以用来显式的标记UTF-16 数据流的字节顺序。.大端编码方案, U+FEFF 字符表示 zero-width nonbreaking space, 而 U+FFFE 则是一个非法的 Unicode字符。因此,编码器可以使用这个字节顺序 FE FF 或 FF FE 来判断字节顺序。当读取 Unicode 数据时,Python会自动移去这个标志。
'utf-16-be' 编码 显式指定届UTF-16 大端编码(big endian), 'utf-16-le' 显式指定 UTF-16 小端编码(little ending)。
尽管已经有多种 UTF-16 的扩展以支持更多字符,目前的 Python 并不支持任何这样的扩展。
'unicode-escape' 及 'raw-unicode-escape' 编码:
这些编码方法被用来转换 Unicode 字符串到 Python使用的 Unicode 字符串及原始Unicode字符串。举例来说:
Toggle line numbersToggle line numbers
1 s = u'\u14a8\u0345\u2a34'
2 t = s.encode('unicode-escape') #t = '\u14a8\u0345\u2a34'
1.6.2. Unicode 字符属性
除了实现输入输出之外, 使用 Unicode 的程序必然会有测试 Unicode 字符属性的需要(是否大小写、是否数字、是否空白等等)。 unicodedata 模块提供了这些 unicode字符数据库。. 常规字符属性可以通过 unicodedata.category(c) 函数得到. 例如, unicodedata.category(u"A") 返回 'Lu', 表示这个字符是一个大写字符。更多关于Unicode 字符数据库及 unicodedata 模块的细节,请参阅附录A。
要解决这些问题, 只能根据特定的编码规则将 Unicode 字符串进行客观表示。这些规则定义了如何将 Unicode 字符表示为字节序列。在第四章, 针对 unicode()及 s.encode() 首先介绍了编码规则。举例来说:
Toggle line numbersToggle line numbers
1 a = u"M\u00fcller"
2 b = "Hello World"
3 c = a.encode('utf-8') # Convert a to a UTF-8 string
4 d = unicode(b) # Convert b to a Unicode string
codecs 模块用类似的技术解决了 Unicode 的输入输出问题。 codecs 模块拥有一系列转换函数依据不同的编码方案完成字节数据和 Unicode 字符串的转换。通过调用 codecs.lookup(encoding) 函数来选择一种编码方案。这个函数返回一个包括四个元素的 tuple (enc_func, decode_func, stream_reader, stream_writer ). 举例来说:
Toggle line numbersToggle line numbers
1 import codecs
2 (utf8_encode, utf8_decode, utf8_reader, utf8_writer) = \
3 codecs.lookup('utf-8')
enc_func (u [,errors ]) 函数接受一个 Unicode 字符串 u ,返回值是tuple(s , len).其中 s 是转码后的 8-bit 字符串(内容为 u 的一部分或全部), len 是被成功转换的 Unicode 字符数. decode_func(s [,errors]) 函数接受一个 8-bit 字符串,返回值是 tuple(u, len)。其中 u 是一个 Unicode字符串(内容为 s 的一部分或全部),len 是被成功转换的字符数。errors 决定转化过程中的错误如何处理,它的值可能是 'strict' 或 'ignore' 或 'replace'。若是 'strict'模式, 编码错误将引发 UnicodeError 异常。 若是 'ignore' 模式, 编码错误将被忽略。若是 'replace' 模式,无法转换的编码将被替换为 '?' 字符(Unicode字符U+FFFD或8-bit字符 '?')。
stream_reader 用来对文件对象进行封装,以支持 Unicode 数据读取. 调用 stream_reader (file) 返回封装后的文件对象,它的 read(), readline(), 及 readlines() 方法支持读取 Unicode 字符串数据. stream_writer 用来对文件对象进行封装,以支持将 Unicode 字符串写入文件。调用 stream_writer(file) 返回封装后的文件对象,它的 write() 和 writelines() 方法将 Unicode 字符串按给定的编码转换为字节流写入文件中。
下面的例子演示了如何使用这些方法处理 UTF-8 编码的 Unicode 数据:
Toggle line numbersToggle line numbers
1 # 输出 Unicode 数据到文件
2 ustr = u'M\u00fcller' # 一个Unicode 字符串
3
4 outf = utf8_writer(open('foo','w')) # 创建 UTF-8 字节流
5 outf.write(ustr)
6 outf.close()
7
8 # 从一个文件读取 unicode 数据
9 infile = utf8_reader(open('bar'))
10 ustr = infile.read()
11 infile.close()
当处理 Unicode文件时, 数据编码通常内嵌在文件本身当中。举例来说,XML 解析器根据文件的前几个字节'' 来判断文件编码. 如果最初的四个值是 3C 3F 78 6D ('
用类似下面的代码来读取文档的编码:
Toggle line numbersToggle line numbers
1 f = open("somefile")
2 # Determine encoding
3 ...
4 (encoder,decoder,reader,writer) = codecs.lookup(encoding)
5 f = reader(f) # Wrap file with Unicode reader
6 data = f.read() # Read Unicode data
7 f.close()
1.6.1. Unicode 数据编码
表 9.2 列出了codecs模块中目前正在使用的所有编码
表 9.2. codecs 模块中的全部编码器
编码 描述
'ascii' ASCII 编码
'latin-1', 'iso-8859-1' Latin-1 或 ISO-8859-1 编码
'utf-8' 8-bit 变长编码
'utf-16' 16-bit 变长编码
'utf-16-le' UTF-16, 显式小端编码方案
'utf-16-be' UTF-16, 显式大端编码方案
'unicode-escape' 和 u"string " 格式相同
'raw-unicode-escape' 和 ur"string "格式相同
下面的段落描述了各种编码的细节:
'ascii' 编码:
'ascii' 编码, 字符值的范围被限制在[0,0x7f] 和 [U+0000, U+007F]。超出这个范围的任何字符都是非法的。
'iso-8859-1' 或 'latin-1' 编码:
字符可以是任意的 8-bit 值([0,0xff] 及 [U+0000, U+00FF]). 取值范围 [0,0x7f] 内的字符对应 ASCII 字符集,取值范围 [0x80,0xff] 内的字符对应 ISO-8859-1 或 扩展 ASCII 字符集。超出 [0,0xff] 取值范围的任何字符都会造成错误。
'utf-8' 编码:
UTF-8 是一种变长编码,它能表示所有的Unicode字符。一个单独的字节用来表示值为 0–127 的 ASCII 字符。所有其它字符均被表示为多字节序列(双字节或3字节)。这些字节的编码见下表
Unicode 字符 Byte 0 Byte 1 Byte 2
U+0000 - U+007F 0nnnnnnn
U+007F - U+07FF 110nnnnn 10nnnnnn
U+0800 - U+FFFF 1110nnnn 10nnnnnn 10nnnnnn
对两字节序列, 第一个字节的前三个比特总是 110. 对三字节序列, 第一个字节的前三个比特总是 1110. 多字节序列的所有后来字节的前两个比特都是 10。
UTF-8 格式一个字符最多可以使用六个字节。 Python 中, 四字节 UTF-8 序列被称为代理对,用来对一对 Unicode 字符进行编码。这一对字符的取值都在[U+D800, U+DFFF]范围内并组合成一个 20-bit 的值. 代理对这样编码:四字节序列 111100nn 10nnnnnn 10nnmmmm 10mmmmmm 被编码成这样一对: U+D800 + N , U+DC00 + M , 其中 N 是高10位, M 是低十位。五字节和六字节 UTF-8 序列(开始位分别为 111110 和 1111110) 用来对32比特值的Unicode字符进行编码。Python目前不支持五字节和六字节UTF-8序列。如果数据流中存在这样的数据会引发 UnicodeError 异常。
UTF-8 编码对旧程序支持的相当好. 首先,标准 ASCII 字符的编码没有发生任何改变。这意味着 UTF-8 编码的 ASCII 字符串与传统的 ASCII 字符串完全相同。其次, UTF-8 编码的多字节序列未内嵌 null 字节。这样现有的基于 C 库的软件和程序所使用的 null-结尾的 8-bit 字符串可以与 UTF-8 字符串相容. 最后,UTF-8 编码 保留了字符串的字典顺序。也就是说如果 a 和 b 是 Unicode 字符串并且 a < b, 则当 a 和 b被转化为UTF-8编码后, a < b 仍然成立。因此,写给 ASCII 字符串的排序算法及其它与顺序有关的算法也一样可以工作在 UTF-8 编码上。
'utf-16' , 'utf-16-be' , and 'utf-16-le' 编码:
UTF-16 是一种变长16位编码,其中 Unicode 被记录为 16-bit 值。如果未指定字节顺序,则默认为大端法编码方案。另外,一个特殊的字符 U+FEFF 可以用来显式的标记UTF-16 数据流的字节顺序。.大端编码方案, U+FEFF 字符表示 zero-width nonbreaking space, 而 U+FFFE 则是一个非法的 Unicode字符。因此,编码器可以使用这个字节顺序 FE FF 或 FF FE 来判断字节顺序。当读取 Unicode 数据时,Python会自动移去这个标志。
'utf-16-be' 编码 显式指定届UTF-16 大端编码(big endian), 'utf-16-le' 显式指定 UTF-16 小端编码(little ending)。
尽管已经有多种 UTF-16 的扩展以支持更多字符,目前的 Python 并不支持任何这样的扩展。
'unicode-escape' 及 'raw-unicode-escape' 编码:
这些编码方法被用来转换 Unicode 字符串到 Python使用的 Unicode 字符串及原始Unicode字符串。举例来说:
Toggle line numbersToggle line numbers
1 s = u'\u14a8\u0345\u2a34'
2 t = s.encode('unicode-escape') #t = '\u14a8\u0345\u2a34'
1.6.2. Unicode 字符属性
除了实现输入输出之外, 使用 Unicode 的程序必然会有测试 Unicode 字符属性的需要(是否大小写、是否数字、是否空白等等)。 unicodedata 模块提供了这些 unicode字符数据库。. 常规字符属性可以通过 unicodedata.category(c) 函数得到. 例如, unicodedata.category(u"A") 返回 'Lu', 表示这个字符是一个大写字符。更多关于Unicode 字符数据库及 unicodedata 模块的细节,请参阅附录A。
2008年12月24日星期三
2008总结
时间过得真快,一年又快到尽头了,又是一年总结的时候了。今年是我的本命年,原本听说本命年的人的际遇会很极端,要不就是很好,要不就是很差。我也很低调地度过了我生命中的第二个本命年,今年也的确发生了一些蛮大的事情吧。那就顺着说一下,总结一下经验,同时也展望一下明年,希望那个明年做得更好一点。
08年初在原公司第一个独立完成的产品上线,互联网上第一次有了我的作品,小庆贺一下。并且开始打羽毛球,基本每个周末都会去一次,还买了一只100多块的球拍,感觉身体慢慢好了一点,也习惯了这样的生活习惯。接着就是在一次偶然的和一个网友的聊天中被“看上”,接受了另一家公司的电话面试,并且还跑到了广州见了现在的老大一面,并且聊了一些工作上的看法,不过感觉并不太好,而且当时我去广州的目的也并不是面试,而是想尝一次我一直想喝的大加司的奶茶(现在已经不想喝了,听说都是奶精泡的),不过回来后竟然收到了offer,而且待遇给的还不错,于是决定了我生命中的第一次跳槽。
向原公司提出了离职,因为还没满合同期,原本需要交违约金,不过公司做法不太正规,被我搬出劳动仲裁吓到了,于是免了巨额违约金,呵呵。还好,于是还比较顺利地走人了,不过其实还是有点不舍得的,原公司还是一个比较适合做技术的地方,可惜比较吝啬:)还记得搬离深圳的前一天狂风暴雨,而当时住的地方收拾得很乱,一塌糊涂,我们当时窝在屋里点了一个永和大王的牛柳饭,还蛮好吃的:)在广州住的地方离公司当时的地址很近,于是我过了一段很闲适的日子,每天中午都回住的地方吃中午饭,并且打个瞌睡,下午洗把脸再去上班,这是当年上学的时候才有的待遇啊!!!!可惜这种日子不能维持多久,公司就搬到了天河城的写字楼 ,于是每天开始逼地铁,直至今天。
今年比较成功的地方就是实现了工作选择上的一个跳跃,可惜很多东西都是福兮祸所倚,在这里我过得并不算十分开心,也许不太和我自己的性格吧,不过世事往往没有十全十美的,也许这样才能使我有动力去追寻自己的梦想吧。展望2009,最大的希望当然还是事业再上一层楼啦,感情方面,希望继续稳定恩爱,两个人能够磨合得更好,吵架能够再少一点。暂时没什么更具体的想法啦,很多东西要一步步地去走,希望新年更多阳光,少点乌云。
今年比较成功的地方就是实现了工作选择上的一个跳跃,可惜很多东西都是福兮祸所倚,在这里我过得并不算十分开心,也许不太和我自己的性格吧,不过世事往往没有十全十美的,也许这样才能使我有动力去追寻自己的梦想吧。展望2009,最大的希望当然还是事业再上一层楼啦,感情方面,希望继续稳定恩爱,两个人能够磨合得更好,吵架能够再少一点。暂时没什么更具体的想法啦,很多东西要一步步地去走,希望新年更多阳光,少点乌云。
2008年12月8日星期一
dynamic_cast详解
作为四个内部类型转换操作符之一的dynamic_cast和传统的C风格的强制类型转换有着巨大的差别。除了dynamic_cast以外的转换,其行为的都是在编译期就得以确定的,转换是否成功,并不依赖被转换的对象。而dynamic_cast则不然。在这里,不再讨论其他三种转换和C风格的转换。
首先,dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。
先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚方法,也就无法判断一个基类指针变量所指对象的真实类型, 这时候,dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.而这种转换其实并不需要dynamic_cast参与.
也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的.
下面看一个例子:
struct B1{
virtual ~B1(){}
};
struct B2{
virtual ~B2(){}
};
struct D1 : B1, B2{};
int main()
{
D1 d;
B1* pb1 = &d;
B2* pb2 = dynamic_cast(pb1);//L1
B2* pb22 = static_cast(pb1); //L2
return 0;
}
上述定义中可以看到,B1和B2是不相关的类,从L1可以看到,dynamic_cast允许这种转换:只要B1存在多态方法.
L2将编译失败,static_cast并不允许两个完全不相干的类互相转换.
dynamic_cast的这种特性,在提取一个对象的某个接口的时候,非常有用,它很类似于实现了COM的QueryInterface的功能。
正好在网上看到一个讲解强制转型的文章:
http://www.xker.com/article/articleview/2005-8-23/article_view_2732.htm
文中这样描述:
--
dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。
---这个描述是不完整的,dynamic_cast 固然可以实现完全的向下转型,也可以实现更为强大的QueryInterface的功能。
首先,dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。
先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚方法,也就无法判断一个基类指针变量所指对象的真实类型, 这时候,dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针.而这种转换其实并不需要dynamic_cast参与.
也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的.
下面看一个例子:
struct B1{
virtual ~B1(){}
};
struct B2{
virtual ~B2(){}
};
struct D1 : B1, B2{};
int main()
{
D1 d;
B1* pb1 = &d;
B2* pb2 = dynamic_cast
B2* pb22 = static_cast
return 0;
}
上述定义中可以看到,B1和B2是不相关的类,从L1可以看到,dynamic_cast允许这种转换:只要B1存在多态方法.
L2将编译失败,static_cast并不允许两个完全不相干的类互相转换.
dynamic_cast的这种特性,在提取一个对象的某个接口的时候,非常有用,它很类似于实现了COM的QueryInterface的功能。
正好在网上看到一个讲解强制转型的文章:
http://www.xker.com/article/articleview/2005-8-23/article_view_2732.htm
文中这样描述:
--
dynamic_cast 主要用于执行“安全的向下转型(safe downcasting)”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。
---这个描述是不完整的,dynamic_cast 固然可以实现完全的向下转型,也可以实现更为强大的QueryInterface的功能。
订阅:
博文 (Atom)