正文

C++标准阅读笔记2007-04-27 22:13:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/lingdlz/25283.html

分享到:

// 以下是个人阅读C++标准时记录的一些容易被忽略的语法
// 希望对你有所帮助。


1,换页符 '\f' 如何换页 :
2,在常量后面加上 L或者U表示长整形或者无符号整形,在 int long长度不同时很有必要
   但是加上可以提高程序的可移植性 long a = 23L;
3,浮点型可以处理三百多位的运算
4,不但变量有内存地址,函数同样也有,这里不了解
5,C ++可以这样输出字符串 :cout<<"skdfjsdf\n"
      "ksdfjlksdfjsdfs\n"
      "ksdfjssssssssdfsdfsdfjsdlfs\n";
6,常量类型的变量不能作为左值
7,移位运算,变量本身不变如 int i = 2; j = i<<2; i 没变

9,a = a + 1 与 a += 1 区别,前者对 a 计算两次而后者只计算一次
10,cout<<endl; 与 cout<<'\n';的区别是前者在输出换行符后更新输出流而后者只输出个换行符
    当然这个区别不是在所有的编译器中都有体现
11,在C++中 main() 默认返回整形值,默认有两个参数
12,我晕 main()函数在VC++6.0中允许递归调用
13,可变函数参数: void test(int,...);
17,良好的程序设计风格,每个函数完成一个特定的功能
18,无名形参 void test(int i,int); // 调用时必须给出无名形参所在值 test(2,4);
19,C++支持默认参数
20,内联函数,C++标准没有明确说明必须在调用之前声明内联函数,使用内联函数有两种情况
    取带宏或者把一个大函数分成多个内联函数,这样可以改进程序的可读性
21,之所以函数可以递归是因为,每当函数被调用时都会把参数和他的局部数据对象拷贝到一块
    专有的内存区。
22,安全连接,为解决同名函数的带来的问题,C++采用了名字重组技术,给编译器内部的函数标识符
    重命名,重组技术不同的编译器有不同的算法
23,连接说明,C++编译器对函数名重组,如果他调用其它编译器如C,汇编等,这些编译
    器并不重组函数名,因此会导致函数无法调用,这时可以使用连接说明如:
   extern "C"{
 #include "test.h"  // 告诉C++编译器,该头文件的库函数都是用C编译器编译
   } 这样C++就不会对 test.h 里的函数重组,因此就可以正确调用了。
24,对C代码最好不要使用 // 注释,因为它不是C标准,虽然某些编译器支持
25,在修改别人的程序时,即使不喜欢那种风格,也应该和原程序的书写风格保持一致
26,一个表达式在程序中被用于检验真假时就称其为一个条件
27,标准 C++在 std名字空间内包含了所有的标准C库,因此多熟悉标准C库很划算呵呵,因为我喜欢C
28,在if语句里声明变量,1)只能是可转换为布耳型的变量2)只能在最开始申明不能放到括号里
    如if((int i=test())=0) ...; 错误 !
    这样的规定很没有道理哦 ,就象请喝酒就不能吃菜,晕 !
29,goto语句不能跳过包含隐式或显示初始化的变量声明语句,例如:
    #include<iostream>
    using namespace std;

 void main()
 {
     int a = 2;
     if(a == 2)
      goto t;
     int b = 3;
  t:
     return ;
 } // 不能通过编译,在C语言里不存在这种情况,纠正:int b = 3; int b; b = 3;
             也可以: if(a == 2) goto t; else  int b = 3;
30,全局作用域解析运算符 :: 解决局部变量屏蔽全局变量的问题
31,const 类型修饰符, const 变量可能占用内存也可能不占用内存,当然如果程序中有取
    const 类型变量地址的操作,则编译器必须为其分配内存,否则编译器自由决定是否把
    它变为常量
32,volatile 类型修饰符,阻止编译器对变量进行优化。设想:程序把一个变量的地址传递给
    一个外部指针,程序和系统的某个中断服务例程通过指针修改变量的内容,如果编译器优化时
    把变量放入寄存器里,那么中断就不起作用了。
33,联合的初始化,只能对联合的第一个成员变量进行初始化,初始化值放在一对大括号中,只需要一个
    初始化值就够了,他的类型必须和联合的第一个成员相一致。
34,匿名联合,union { int i; int j; } i,j共用一块内存区。,省掉了联合的名字,对于全局匿名联合必       
    须声明为静态
35,我们可以给指针变量任意的值,不过,要让它接受得费点事,在采用分段内存结构的计算机中编译程序时
    如果程序的数据段和代码段是分开的,那么指向函数和指向数据的指针长度可以不一样
36,指向 const 型变量的指针,const char *str; str不能改变所指内存地址的值,如下:
   const char s1[] = "fskdfj"; char *cp1 = s1; 错误const char *cp2 = s1;
   // 可以 void t(char *ps); void t2(const char *ps); t(s1); //错误 t2(s1); 正确
37,const 型的指针变量 char* const p; p 指针经过初始化后就不可被修改,修正

38,C++允许任何类型的指针自动转为 void 型,但从 void 到其它类型则必须强制转换
39,sizeof 运算符时,操作数是一个类型时必须加上括号,是一个变量名时,可以不加
40,用sizeof计算数组长度非常有效,因为数组长度改变时,sizeof 不需要修改
41,获取浮点数的整数部分的方法:2323.23  int i = (int)2323.23;
42,C++允许用变量定义数组的大小,如: int size; cin>>size; int* p = new int[size];
43,以const引用作为函数返回值,防止被引用变量的修改
44,不能返回局部变量的引用,因为已经脱离作用域,引用一个不存在的对象会导致错误
45,如果某个对象可能不存在则使用指针,否则可以使用引用变量
46,<cassert> 使用 assert 宏,#define NDEBUG
47,setjmp(),longjmp()函数
48,条件编译没有用到极致,晕 !
49,不常见的宏指令 #line:用来改变编译器指出警告和错误信息的文件名和行号
    #pragma:没有正式定义,编译器可以自定义其用途,典型用法是禁止或允许某些烦人的警告
    在VS2005中#pragma once 取代:#ifndef xxx #define xxx ...  #endif    修正
50,模板函数能够编译通过,并不意味着函数能正确的执行
51,全局变量被自动初始化为 0 ,但局部变量不自动初始化
52,没有参数或者都有默认值的构造函数称为默认构造函数,默认构造函数很重要,如果没有默认构造
    函数将无法初始化对象数组,因为类对象数组不允许用初始化值表来匹配某个构造函数参数表
53,转换构造函数,仅有一个参数,且该参数是不同于该类的一个数据类型,调用方法和其它构造函数
    如 cname::cname(type); type = cname; 可以,但如果在前面加一个 explicit 则它就成了显示
    构造函数 type = cname ; 编译会通不过;(隐式转换和显示转换很有意思啊 !)
    拷贝构造函数,只有一个参数其参数是他所属类的一个对象:调用情况:1)用已存在的对象去初始
    化同一个类的另一个函数2)在函数参数中以传值方式传递类对象的拷贝3)类对象的值被用作函数的
    返回值,赋值与初始化的区别:赋值是在两个已经存在的对象间进行,初始化是创建一个新对象,其
    值来源于另一个已经存在的对象。
54,成员转换函数,将一个类对象转变为其它类型:需要用到 operator 关键字:
    ex: A::operator long(),将 A 对象转换为long型数值 B::operator type() 将B转换为 type 类型
55,静态成员函数没有this指针,只能访问静态数据成员
56,类的常量数据成员以及引用数据成员必须在参数初始化表里进行,不能在构造函数里进行。
57,常量对象不能调用非常量函数:如:
 class student{
 public:
  void put();
 };
 void  student::put(){
  cout<<"skdfjs"<<endl;
 }
 int main(){
  const student s;
  s.put(); // 编译不能通过,有的编译器可能是警告。因为编译器认为 put()函数可能
  return 0; // 会修改常量对象 s
 }
 // 如果不管某个对象是否是常量型的,对象必须修改某个值,C++标准委员会为解决这个问题引
 // 入了 mutable关键字,常量类型的对象以及常量函数可以修改它,与const 是一对冤家
58,重载运算符 ++, 带无名参数 int 的表示后缀自增运算符 (i++)
59,class& f(class& c); 与 class f(class& c); 的区别是前者返回时不生成临时的匿名对象,而后者
    返回时调用拷贝构造函数产生一个匿名对象。
60,重载的[]下标运算符不能是静态的成员函数,也不能用类的友元来实现。
61,继承体系中,如果没有访问说明符,对于类默认为私有继承,而对于结构为公有继承
62,虚基类 class test: virtual public  vclass{...},虚基类的构造函数不能带参数 有待验证
       虚拟继承主要用于解决多重继承里的问题

63,模板和宏的区别是模板为相同的对象只生成一种代码,而宏是在使用处展开
64,派生类修改基类的行为时使用继承,当这种关系是管理类的对象而不是修改行为时应该使用模板,
    模板的参数不要太多 ???
65,类模板的默认参数 template<class T,class T2=int> T2默认为整形 int ,模板增加了对通用对象和函数的支持
66, explicit 限定词,关键字explicit用来禁止编译器隐式调用该构造函数

/////////////////////////////////////////////////////////////////////////////////////////////////////
67,面向对象的程序设计对设计的改进和对编程效率的提高并不意味着传统的程序设计方法已经过时,欢呼 !
/////////////////////////////////////////////////////////////////////////////////////////////////////

68,clog向标准错误设备写入内容
69,cerr ,cout ,cin 使用缓冲,把输出(入)的字节存入到某个缓冲区,直到如下某个事件发生
    才把数据写入与之关联的实际设备1)缓冲区满2)刷新缓冲区3)程序被终止4)cout 从 cin对象读
    取数据
70,cout<<setw(20)<<str<<endl; 在VS下不行 ???在VC下写不行,晕,没有加入头文件 <iomanip>
    格式化标志 (如 std::ios::hex)可以使用操纵算子 setiosflags(...)[resetiosflags(...)]
    以及成员函数(ostream) setf()[unsetf()],如:(成员函数需要对象来调用,而操纵算子可以直接
    插入流中)
 int test = 123;
 cout.setf(std::ios::oct);
 cout<<test<<endl;
 cout.unsetf(std::ios::oct);
 cout<<test<<setiosflags(std::ios::oct)<<"after set"<<test<<endl;
 // 晕以上语句在VS中都是输出 123
 cout<<hex<<test<<endl;
 cout<<oct<<test<<endl;
 // 这几条语句倒是有用
71,成员函数 (cout)write()把任意内存块的内容以二进制格式写入流中,它只接受 char,unsigned char
    类型的指针,write(char*,size); read()与write()是一对输入输出函数,通常用于文件的输入输出
72,提取运算符 >> 略过输入时的空白字符,而成员函数 get(),getline()不略过
73,定位文件流的位置 seekg() seekp(),获取位置 tellg() ,tellp()
74,打开文件同时用于读写 ???,打开关闭文件流  open(),close()
75,测试错误:eof() 测试是否到达文件结尾,bad()程序试图做非法的事情如查找的位置超越了文件尾
    fail() 输入输出操作失败(如试图打开一个不存在的文件或磁盘已满时向磁盘写数据)
    good() 与 fail() 反 ,打开二进制文件 tfile.open("test.bat",std::ios::binary)
76,复数类:std::complex
78,标准C++默认的数值显示方法: std::ios::scientific,在科学记数法下,setpricision(x) 指定的是
    有效数字,而在定点小数下指定的是精度即小数点后的数,在计算机里精度最多没有超过20位 <=18
79,所谓的流是一系列的字节,它可以从一种类型的设备流向另一种类型的设备
80,有这个东西吗: std::ios::nocreate,std::ios::noreplace
81,文件与流的关联与解除,可以通过 open(),close() 函数,声明时声明一个没有初始化的文件流即可
82,文本文件与二进制文件的区别:写入 \n 符号时 ,二进制文件只写入回车符(0x0a)而文本文件写入
    回车(0x0a) 以及 换行符(0x0d),读取时二进制文件不变,而文本文件将 (0x0a , 0x0d)变为 \n 写
    入内存。从这里知道文本文件在内存里的大小和在磁盘里的大小是不同的,而二进制的没变。
83,用fstream创建的文件对象可以同时用于读写。但得先输入,如果是先输出内容,然后在向文件写会
    写不进去,这个我看作用不大。

#include <fstream>
#include <iostream>
using namespace std;

int main(){
 char j;
 fstream f("test.txt");
 j = f.peek();
 cout<<j<<endl;
 f.put('k');
 return 0;
}
// 以上程序,执行前 test.txt的内容:deng
// 执行后还是: deng。k 没有写进去

#include <fstream>
#include <iostream>
using namespace std;

int main(){
 char j;
 fstream f("test.txt");
 f.put('k'); 
 j = f.peek();
 cout<<j<<endl;

 return 0;
}
// 以上程序,执行前 test.txt的内容:deng
// 执行后还是: k蚽g。k 写进去了,却出现了乱码

84,链表附值时 my.assign(first,end); first和end迭代器不能是链表 my 自身的值
85,集合(set,multiset)里的upper_bound 和 lower_bound 老是不对劲,使用方法不明???
86,int i = 2; cout<<i<<" "<<++i<<endl;  将输出 3 3 因为先计算 ++i
88,如何在集合里自定义谓词
89,longjmp()函数在C++中使用来展开堆栈不起作用,因为堆栈中的自变量包含了类对象
    那些对象需要运行其析构函数。而C++的异常处理机制展开堆栈的过程虽然和 longjmp()
    函数类似,但它能够正确的调用对象的析构函数,(try,catch)throw语句展开堆栈首先
    调用析构函数清除try块内定义的所有对象,然后throw调用相匹配的 catch 处理块,传递
    参数对象。但是有个问题:如果某个资源的释放出在抛出异常的后面,该资源就不能被释放
    如: int test(){ 
  char *p = new char[4];
  ....
  if(...)
   throw 4;
  delete [] p;
 }
    则 p 在堆中分配的内存没有被释放。Stroustrup 博士建议所有资源都在资源管理类中的自动
    化实例中解决,当异常发出,展开堆栈时,该类的析构函数就释放所有资源,另一种方法是全局
    化这些资源。于是catch模块就能够清光所以东西了。怎样才能确定这些资源已经释放 ???
90,异常指定是函数声明的一部分,你必须把它包含在函数原型以及函数定义头模块中,否则
    当遇到函数的第二次声明时编译器就会报告类型不匹配。VC里好象只需要在声明中指定就可以了。
    如果一个函数抛出了一个它没有指定的异常,这个异常就被传递给unexpected() 系统函数。
    一个没有异常指定的函数可以抛出任何异常,一个带有省略号的参数列表的 catch 模块,可以
    捕获所有未经捕获的异常。与try模块相关联的一组模块当中,catch(...)模块必须最后出现。
    没有被捕获的异常,一个未经捕获的异常指的是没有为其指定 catch 的模块的异常,或者由作为
    一次异常发出结果的析构函数抛出,这样的异常导致terminate()函数被调用。
91,无名名字空间,定义名字空间时省略名字空间的名称,事实上无名名字空间中定义的标识符被置为
    全局的名字空间。可以给名字空间取别名. 如: mystd = std; 则 mystd 和 std是一样的
92,动态类型转换,将基类引用或指针转换为一个派生类引用或指针,或者反之。仅仅当基类至少有一个
    虚函数时,可以使用动态类型转换。

阅读(5398) | 评论(5)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册