5/17/2008

C++ links

{C++ 基础} {C++ 高级} {C#界面,C++核心算法} {设计模式} {C#基础}
http://www.cppblog.com/mzty/category/249.html

5/15/2008

public,private,protected继承

对于一个父类(基类),
如果声明一个成员为private,就说明这个东东使我的,不能让其他人用,包括子孙。
如果是protected,我就会告诉我的子孙,你们要小心的用,但绝对不能让外人使用。
如果说是public,那就是说,这个东东大家随便用吧。

对于一个子类(从基类继承而来的),
private是一个吝啬的继承者,他将从祖辈继承下来的东西统统藏起来,不让别人碰触(包括自己的子孙)。(当然他也只能使用祖辈授予其的权力,即只能使用祖辈中的protected和public)。
protected是一个有保护意识的继承者,他将从祖辈继承下来的东西,只允许自己的子孙使用(即使以前祖辈的东西是公众都可以使用的public)。
public是一个循规守据,他不关心祖辈的东西,原来是什么规矩就是什么

5/14/2008

位段

C语言中的结构是有实现位段的能力的,噢!你问它到底是什么形式是吧?这个问题呆会给你答案。让我们先看看位段的作用:位段是在字段的声明后面加一个冒号以及一个表示字段位长的整数来实现的。这种用法又被就叫作“深入逻辑元件的编程”,如果你对系统编程感兴趣,那么这篇文章你就不应该错过!
  我把使用位段的几个理由告诉大家:1、它能把长度为奇数的数据包装在一起,从而节省存储的空间;2、它可以很方便地访问一个整型值的部分内容。
  首先我要提醒大家注意几点:1、位段成员只有三种类型:int ,unsigned int 和signed int这三种(当然了,int型位段是不是可以取负数不是我说了算的,因为这是和你的编译器来决定的。位段,位段,它是用来表示字段位长(bit)的,它只有整型值,不会有7.2这种float类型的,如果你说有,那你就等于承认了有7.2个人这个概念,当然也没有char这个类型的);2、成员名后面的一个冒号和一个整数,这个整数指定该位段的位长(bit);3、许多编译器把位段成员的字长限制在一个int的长度范围之内;4、位段成员在内存的实现是从左到右还是从右到左是由编译器来决定的,但二者皆对。
  下面我们就来看看,它到底是什么东西(我先假定大家的机器字长为32位):
  Struct WORD
  {
unsigned int chara: 6:
unsigned int font : 7;
unsigned int maxsize : 19;
  };
  Struct WORD chone;
  这一段是从我编写的一个文字格式化软件摘下来的,它最多可以容纳64(既我说的unsigned int chara :6; 它总共是6位)个不同的字符值,可以处理128(既unsigned int font : 7 ;既2的7次方)种不同的字体,和2的19次方的单位长度的字。大家都可以看到maxsize是19位,它是无法被一个short int 类型的值所容纳的,我们又可以看到其余的成员的长度比char还小,这就让我们想起让他们共享32位机器字长,这就避免用一个32位的整数来表示maxsize的位段。怎么样?还要注意的是刚才的那一段代码在16位字长的机器上是无法实现的,为什么?提醒你一下,看看上面提醒的第3点,你会明白的!
你是不是发现这个东西没有用啊?如果你点头了,那你就错了!这么伟大的创造怎么会没有用呢(你对系统编程不感兴趣,相信你会改变这么一个观点的)?磁盘控制器大家应该知道吧?软驱与它的通信我们来看看是怎么实现的下面是一个磁盘控制器的寄存器:
│←5→│←5→│←9→│←8→│←1→│←1→∣←1→∣←1→∣←1→∣
  上面位段从左到右依次代表的含义为:5位的命令,5位的扇区,9位的磁道,8位的错误代码,1位的HEAD LOADED,1位的写保护,1位的DISK SPINNING,1位的错误判断符,还有1位的READY位。它要怎么来实现呢?你先自己写写看:
  struct DISK_FORMAT
  {
   unsigned int command : 5;
     unsigned sector : 5;
   unsigned track : 9 ;
   unsigned err_code : 8;
   unsigned ishead_loaded : 1;
   unsigned iswrit_protect : 1;
   unsigned isdisk_spinning : 1;
   unsigned iserr_ocur : 1;
   undigned isready :1 ;
  };
  注:代码中除了第一行使用了unsigned int 来声明位段后就省去了int ,这是可行的,详见ANCI C标准。
  如果我们要对044c18bfH的地址进行访问的话,那就这样:
  #define DISK ((struct DISK_FORMAT *)0x044c18bf)
  DISK->sector=fst_sector;
  DISK->track=fst_track;
  DISK->command=WRITE;
  当然那些都是要宏定义的哦!
  我们用位段来实现这一目的是很方便的,其实这也可以用移位或屏蔽来实现,你尝试过就知道哪个更方便了!

C++位操作

[ 转 ] http://phil2360.spaces.live.com/blog/cns!71CD456F35382A94!132.entry
C++位操作包括两种:传统的C语言方式的位操作和C++中利用bitset容器的位操作

一、传统的C方式位操作:
1.基本操作:
使用一个unsigned int变量来作为位容器。
2.操作符:
| 按位或操作符:result=exp1|exp2;当exp1和exp2中对应位中至少有一个为1时,result中对应位为1,否则为0。
& 按位与操作符::result=exp1&exp2;当exp1和exp2中对应位全为1时,result中对应位为1,否则为0。
^ 按位异或或操作符:result=exp1^exp2;当exp1和exp2中对应位不相同时,result中对应位为1,否则为0。
~ 反转操作符:将位容器中的所有位都反转,1变为0,0变为1。
<< 按位左移操作符:exp<>> 按位右移操作符:exp>>n,将容器中所有的位向右移n位,空出的位用0填充。
|=,&=,^= 分别对应|&^三种操作符的复合操作符。
3.常用操作
这里我们假设有一个result的unsigned int变量用来储存32个学生的成绩(通过和不通过分别用0和1),这样result就有33位(result从右至左,从0开始计算位数,在这个例子中0位被浪费)。
(a) 将第27位设置为及格(设作1)其他位不变:
result|=(1<<27) //任意的位值与1作按位或操作其值为1,而与0作按位与操作其值不变
(b) 将第27位设置成不及格(设为0)。
result&=~(1<<27) //任意的位值与0作按位与操作其值为0,而与1作按位与操作其值不变
(c) 反转第27位的值。
result^=(1<<27) //任意的位值与1作按位异或操作其值为1,而与0作按位异与操作其值不变

二、C++中的bitset容器
1.头文件:
#include
2.声明一个容器:
(a)声明一个指定位数的空容器(所有位设为0): bitset bits;
(b)声明一个指定位数并将指定的几个位初始化为相应值的容器: bitset bits(int);
bitdet bits(string&)
总结:bitset模板类中类型参数传递容器的位数,而构造函数参数通过一个int或一个string&值来从右至左初始化容器中的相应值。
3.bitset的基本用法:

4.bitset与传统C位操作及字符串的转换
可以通过to_string()成员将容器转输出为一个string字符串,另外还可以用to_long()成员将容器输出到传统的用于C风格的位容器中。如:
unsigned long bits = bits.to_long();
sting str(bits.to_string());
5.bitset支持所有的位操作符。

effective c++

[ 转 ] http://www.cppblog.com/apollo/articles/8127.html
面向过程的编程风格 Procedural Programming
1. C++ 不允许改变改变 reference 所代表的对象,对 reference 的所有操作与对“ reference 所代表的对象”所进行的操作相同。

2. 以 by reference 方式传递对象当作函数参数时,复制的将是对象的地址,函数中对该对象的所有操作都相当是对传入的对象进行间接操作。

3. pointer 和 reference 的最重要差异是, pointer 可以为空,使用前一定要确保其值非 0 ,而 reference 必定代表某个对象,不必作此检查。

4. 编译器无法根据函数返回值型别来区分两个具有相同名称的函数,因为返回值型别无法保证提供我们一个足以区分不同重载函数的情境。

5. 由函数指针寻址出来的函数,其调用方式和一般函数相同。

6. 可以给函数指针赋予初值,函数名称即代表了函数的地址。

7. 标准的或项目专属的头文件应用尖括号扩住;用户自行提供的头文件则使用引号。



泛型编程风格 Generic Programming
1. Standard Template Library (STL) 主要由两种组件构成:容器 container 和泛型算法 generic algorithm < 通过 function template 技术,实现与容器及数值类型无关之功能 > 。

2. 容器分类: < 切记: vector 可以是空的,数组则否 >

序列式容器 sequential container : vector, list, deque……

关联式容器 associative container : map, set, ……

3. iterator 及 const_iterator 实际上是各个容器定义式内的嵌套 nested 型别。

4. 使用泛型算法须 #include < algorithm > ,使用 function object 须 #include < functional > 。

5. function object 是某种 class 的实体对象,该 class 对 function call 运算符进行了重载操作从而可使 function object 被当作一般函数来使用。令 function call 运算符成为 inline ,从而消除“通过函数指针来调用函数“时需付出的额外代价。

6. function object adapter 会对 function object 进行修改操作。

7. 绑定配接器 binder adapter < bind1nd, bind2nd > 会使 bineary function object 变成 unary function object ; negator adaper < not1, not2 > 会逆转 function object 的真伪值;另外一种有用的 adapter 叫做 instertion adapter 。 #include < iterator >

8. map 被定义为一对数值,其中 key 通常是个字符串,扮演索引角色,另一个数值是 value 。

9. 任何一个 key 值在 map 或 set 内最多只有一份,若要多份相同 key 值,使用 multimap 或 multiset 。



基于对象的编程风格 Object-Based Programming
1 .在 class 内部定义的 member 函数被自动视为 inline 函数。对 inline 函数而言,声明在 class 内部或外部并无区别,同 non-member inline 函数一样,它应于头文件中定义。

2 . Triangular t(); 被编译器视为一个函数定义!并不是声明或定义一个 Triangular 对象!

3 .以某个 class object 作为另一个 object 的初值时,会发生 default memberwise initialization < 实际上是自动产生一个 copy constructor> ,可以为该 class 提供一个 copy constructor 来改变这一默认行为模式。

4 .若有必要为 class 撰写 copy constructor ,则同样有必要为它撰写 copy assignment operator ,除非撰写 copy constructor 的目的仅仅是为了激活编译器实施 NRV 优化。

5 .凡是在 class 主体以外定义的 const member function ,必须同时在声明与定义时都提供 const 关键字, const 紧接于函数参数表之后。

6 . member function 返回一个指向 member data 的 non-const reference ,实际上等于将该 member data 开放出去,允许程序在其它地方加以修改。由于函数可以根据参数 const 与否 而重载,故可以提供两份定义,一份为 const 版本,一份为 non-const 版本。

8. 设计 class 时,鉴定其 const member function 是一件很重要的事情!

9. 将 member data 声明为 mutable 表明:对该 member data 的修改不会破坏 class object 的常数性。

10. 欲以一个对象复制出另一个对象,先确定两个对象是否相同是个好习惯。

11. 运算符的重载规则:不可以引入新的运算符,除了 ., .*, ::, ?: 4个运算符,其它运算符皆可被重载;运算符的操作数 operand 不可改变;运算符的优先级不可改变;运算符函数的参数列中必须至少有一个参数为 class 型别。

12 . increment 和 decrement 运算符的前置及后置版本都可直接施行于 class object 其之上,编译器会自动为后置版产生一个 int 引数,其值必为 0 。

13 .所谓 friend ,具备了与 class member function 相同的存取权限,可以存取 class 的 private member 。

14 .只要 class 设计者显示提供了 copy assignment operator ,它就会被用来取代 default memberwise copy 行为。

15 .当编译器在编译过程中遇到函数调用,例如 lt(ival) , lt 可能是函数名称,可能是函数指针,也可能是一个提供了 function call 的 function object 。如果 lt 是个 function object ,编译器会在内部将此语句转化为: lt.operator(ival) ;

16 . function call 可以接受多个运算符,通常将 function object 当作参数传给泛型算法。

17 .为了取得某个 member function 的地址,只需对函数名称施以取址 address-of 运算符,同时,函数名称之前必须先以 class object 运算符加以修饰,而返回型别及参数表皆不需指明,如: void (classname::*mfptr) (int) = &classname::mfname;

18 .注意所谓的 maximal munch 编译规则,如: static vector< vector< int > > seq; 两个 ”>” 号之间必须加有空格,否则无法成功编译!

19 . pointer to member function 和 pointer to function 的一个不同点是:前者必须通过同类的对象加以调用。 .* 符号是针对 class object 的 pointer to member selection 运算符, ->* 符号是针对 pointer to class object 的 pointer to member selection 。使用它们时注意必须加上外围小括号!如: (classobject.*mfptr)(par);





面向对象编程风格 Object-Oriented Programming
1. 面向对象编程的两项最主要的特性是继承 inheritance 和多态 polymorphism 。

2. 动态绑定 Dynamic binding 是面向对象编程风格的第三个独特概念,即找出实际被调用的究竟是哪一个派生类的函数。而静态绑定 Static binding 则在程序运行之前就决议出应该调用哪一个函数。

3. 多态和动态绑定的特性只有在使用 pointer 或 reference 时才能发挥。

4. staitic member function 无法被声明为虚拟函数。

5. 任何一个类只要有纯虚拟函数,程序就会因其接口的不完整而无法为它产生任何对象,这种类只能作为派生类的子对象 subobject 之用,而且派生类必须为所有纯虚拟函数提供确切的定义。

6. 根据一般规则,凡基类定义有虚拟函数,其 destructor 应声明为 virtual 。但 Stanley B.Lippman 并不建议在这个基类中将其 destructor 声明为 pure virtual ,而是提供空白定义: inline baseclass::~baseclass(){};

7. 对于 public inheritance ,继承而来的 public 成员和 protected 成员,无论在继承体系中的深度如何,都可视为派生类自身拥有的成员。

8. 每当派生类有某个 member 与其基类的 member 同名时,便会遮蔽住基类的那份 member ,若要在派生类中使用继承而来的那份 member ,必须使用 class scope 运算符加以修饰。

9. 不可为抽象基类定义任何对象,它们扮演的角色是每个派生类的 subobject ,基于此点,一般将抽象基类的 constructor 声明为 protected 而非 public 。

10. 派生类之 constructor ,不仅必须为派生类之 data members 进行初始化操作,还需为其基类之 data members 提供适当的值。 copy constructor 和 copy assignment operator 的情形也一样,唯一棘手的是,必须明白调用基类的 copy assignment operator : base::operator = (rhs);

11. 改写基类提供的虚拟函数,派生类提供的定义其函数型别必须完全符合基类所声明的函数原型,包括参数列、返回型别、常量型 const-ness 。但是,对于“返回型别”有个例外:当基类的虚拟函数返回某个基类形式(通常是 pointer 或 reference )时,派生类中的同名函数可以返回该基类所派生出来的型别。

12. 在两种情况下,虚拟函数机制不会出现预期行为: 1 )在基类的 constructor 和 destructor 内; 2 )使用基类的对象而非对象的 pointer 或 reference 。

13. typeid 运算符是 RTTI 的一部分,可以用它来查询多态化的 class pointer 或 class reference ,获得其所指对象的实际型别。 typeid 运算符会返回一个 type_info 对象,其中存储着与型别相关的种种信息。 #include



异常处理 Exception Handling
1. 初学者常犯的错误:将 C++ 异常和 segmentation fault 或是 bus error 这类硬件异常混淆在一起。

2. 在异常处理机制终结某个函数之前, C++ 保证函数中的所有局部对象的 destructor 都会被调用。

3. auto_ptr 是标准程序库提供的 class template ,它会自动 delete 通过 new 表达式配置的对象。 auto_ptr 将 dereference 运算符和 arrow 运算符予以重载,使得我们可以像使用一般指针一样使用 auto_ptr 对象。 #include

4. 如果 new 表达式无法从程序的自由空间 free store 配置到足够的内存,它会抛出 bad_alloc 异常对象。如果要压抑不让 bad_alloc 异常被抛出,可以这么写: somepointer = new (nothrow) someclass; 这样,如果 new 动作失败,返回值为 0 。

5. 标准程序库定义了一套异常类体系 exception class hierarchy ,其最根部是名为 exception 的抽象基类。 exception 声明有一个 what() 虚拟函数,会返回一个 const char* ,用以表示被抛出异常的文字描述。 #include

6. ostringstream class 提供“内存内的输出操作”,输出到一个 string 对象上。当需要将多笔不同型别的数据格式转化为字符串表现式时,它尤其有用。 ostringstream 提供的 str() 可以返回对应的那个 string 对象。 #include

7. iostream 库也对应提供了 istringstream class ,如果需要将非字符串数据的字符串表现式转化为其实际型别, istringstream 可派上用场。

8. string class 的转换函数 c_str() 会返回 const char* !

5/11/2008

C++ reference

FILE -> http://www.cplusplus.com/reference/clibrary/cstdio/FILE.html

c++ file I/O

[origin:]http://simeon.blog.51cto.com/18680/4454
c++ file i/o with binary files using fstream class is a simple task. fstream class has the capability to do both input as well as output operati i.e., read and write. all types of operati like reading/ writing of characters, strings, lines and not to mention buffered i/o are supported by fstream.
operating systems store the files in binary file format. computers can deal with binary numbers. but binary files are not readable by humans. our level of comfort lies with proper ascii or unicode characters. this article deals with how c++ file i/o class fstream can be used for reading and writing binary files. for ascii file operati in c++, refer to c++ text file i/o article.
for our c++ file i/o binary file examples, we assume a struct websites with two members as follows.
// struct for c++ file i/o binary file sample
struct websites
{
char sitename[100];
int rank;
};
write operati in c++ binary file i/o:
there are some important points to be noted while doing a write operation.
• the file has to be opened in output and binary mode using the flags ios::out (output mode) and ios::binary( binary mode)
• the function write takes two parameters. the first parameter is of type char * for the data to be written and the sec is of type int asking for the size of data to be written to the binary file.
• file has to be closed at the end.
// sample for c++ file i/o binary file write
void write_to_binary_file(websites p_data)
{
fstream binary_file("c:test.dat",ios::out|ios::binary|ios::app);
binary_file.write(reinterpret_cast(&p_data),sizeof(websites));
binary_file.close();
}
the above c++ file i/o binary sample function writes some data to the function. the file is opened in output and binary mode with ios::out and ios::binary. there is more specifier ios::app, which tells the operating system that the file is also opened in append mode. this means any new set of data will be appended to the end of file.
also the write function used above, needs the parameter as a character pointer type. so we use a type c reinterpret_cast to typecast the structure into char* type.

read operati in c++ binary file i/o:
this also has a similar flow of operati as above. the difference is to open the file using ios::in, which opens the file in read mode.
// sample for c++ file i/o binary file read
void read_from_binary_file()
{
websites p_data;
fstream binary_file("c:test.dat",ios::binary|ios::in);
binary_file.read(reinterpret_cast(&p_data),sizeof(websites));
binary_file.close();

cout< cout<<"rank :"<< p_data.rank<
}
most of the programs will usually go for ascii text mode files only. but there will be some occasi where the c++ file i/o with binary files will be very useful.
this " c++ file i/o using binary files" article gives some very basic samples for read and write. advanced c++ file i/o operati like seek, checking the file pointer validity etc., are also needed to be learnt while writing bigger programs.
cfile is the class used for handling files in mfc. this class can be used for creating, reading, writing and modifying files. it directly provides unbuffered, binary disk input/output services, and it indirectly supports text files and memory files through its derived classes.
cfile - creating a file:
there are two ways of creating files. one way is to instantiate the cfile object with the file path. this creates the file. the sec way is to call the open function. this also creates the file.
cfile cfile_object( "c:testcodersource_cfile_example.txt", cfile::modecreate|cfile:: modereadwrite);

cfile cfile_object;
cfile_object.open( "c:testcodersource_cfile_example.txt", cfile::modecreate|cfile:: modereadwrite);

the first parameter to both the functi (cfile() c and open()) is the physical path of the file in the disk. the sec parameter is an enumerated constant. this specifies the mode of opening the file object. the above c modecreate implies "create a new file" and modereadwrite means "open the file for both reading and writing".
if the file is opened without specifying the mode c sharedenyn this file can be opened in read mode by other programs. this feature will be necessary for text files, logs created by programs. for creating text files we use cfile::typetext and for binary files cfile::typebinary.
cfile - writing to a file:
the function write is used to write data to the files. the sample code is as follows.

cfile cfile_object;
cfile_object.open( "c:testcodersource_cfile_example.txt", cfile::modecreate|cfile::modewrite);

char szsampletext[100];
strcpy(szsampletext, "sample text for cfile write function example");
cfile_object.write (szsampletext,100);
if there is any need to write text line by line, it is better to use the class cstdiofile.
cfile - reading from a file:
the function read is used to read data from files. the sample code is,

cfile cfile_object;
cfile_object.open( "c:testcodersource_cfile_example.txt", cfile::modecreate|cfile::modewrite);

char szsampletext[100];
uint lbytesread = cfile_object.read (szsampletext,100);
the function returns the number of bytes read from the file. the maximum number of characters read will be the sec parameter of the read function.
cfile - closing the file:
the close function is used to close the file. but the close function need not be called, as the destructor will automatically call it if the file is open. so when the object goes out of scope, the destructor calls close function.
file handling is an important part of all programs. most of the applicati will have their own features to save some data to the local disk and read data from the disk again. c++ file i/o classes simplify such file read/write operati for the programmer by providing easier to use classes.
c++ file i/o classes and functi
there are 3 file i/o classes in c++ which are used for file read/write operations. they are
• ifstream - can be used for file read/input operati
• ofstream - can be used for file write/output operati
• fstream - can be used for both read/write c++ file i/o operati
the most important methods which will be used for any file operati are:
1. fstream::open method - to open the file
2. fstream::operator >> and fstream::operator << - for reading from or writing to the file.
3. fstream::close - flushes all buffer and close the file
reading a text file using fstream class:
there are several ways of reading the text from a file. but all of them have a common approach as follows.
1. open the file
2. read the data
3. close the file
this sample code snippet explains how to use the c++ file i/o stream operators to read data from a file. in all cases the header file fstream.h must be included.
________________________________________
#include
int main()
{
char str[2000];
fstream file_op("c:test_file.txt",ios::in);
while(file_op >> str)
cout < < str ;

file_op.close();

return 0;
}
________________________________________
the class fstream, which is used above is the which is comm used for c++ file i/o manipulations. the c of fstream takes 2 parameters. one is the file path and the sec is the file open mode. there are several open modes, each of them with a different purpose. some of them are ios::in for reading, ios::out for writing, ios::app for appending to the end of file, ios::binary for opening in binary mode etc.,
now for the purpose of this article, as the data is read from the file, the flag ios::in is used. after this, the read operation is c till the end of the file. the while loop ensures a c read till the end of the file or it encounters any abnormal break. if the program is built and run , it displays all the data read from the file. the c++ file i/o read job is done.
but if we look at the output closely, there is a draw back in using this stream operator read. the output misses the white spaces and the end of line characters. in order not to miss these characters we can either use fstream::get() or fstream::getline() methods. here is the example for using fstream getline method.
________________________________________
#include
int main()
{
char str[2000];
fstream file_op("c:test_file.txt",ios::in);
while(!file_op.eof())
{
file_op.getline(str,2000);
cout < } file_op.close();
cout <
return 0;
}

________________________________________
writing to a text file using fstream class:
writing to a text file can also be achieved with the stream operators. this also follows the same order of operati though with a slight difference.
1. open a file - in write mode
2. write to a file
3. close the file
look at the following sample code to see the difference.
________________________________________
#include
int main()
{
fstream file_op("c:codersource_file.txt",ios::out);

file_op<<"test write to file";
file_op.close();
return 0;
}
________________________________________
to modify the data or to seek to a different position inside the file, the c++ file i/o class fstream provides member functi like seekg() etc., these functi can be used to relocate the record insert position to the desired locations.
after all the c++ file i/o operati we do a fstream::close(), to close the file pointer. this is not mandatory. even if this function is not called by the applicati the destructor of the fstream class will close the file when the object goes out of scope.