C++ Notes

前一阵子看c++书时的一点笔记

l 我们知道不带下标操作符的数组名会被解释成指向首元素的指针,当一个函数名没有被调用操作符修饰时会被解释成指向该类型函数的指针。将取地址操作符作用在函数名上也能产生指向该函数类型的指针。

l 编译C++程序时编译器自动定义了一个预处理器名字__cplusplus。在编译标准C 时编译器将自动定义名字__STDC__。

l C++支持两种形式的初始化第一种形式是使用赋值操作符的显式语法形式;在隐式形式中初始值被放在括号中。

l 在对象的定义中,当对象的标识符在定义中出现后,对象名马上就是可见的,因此用对象初始化它自己是合法的,只是这样做不太明智: int num = num;

l 每种内置数据类型都支持一种特殊的构造函数语法可将对象初始化为0, 例如

// 设置ival 为0 dval 为0.0

int ival = int();

double dval = double();

l 引用在内部存放的是一个对象的地址,它是该对象的别名对于不可寻址的值如文字常量以及不同类型的对象,编译器为了实现引用必须生成一个临时对象,引用实际上指向该对象,但用户不能访问它。例如当我们写

double dval = 1024;

const int &ri = dval;

编译器将其转换成

int temp = dval;

const int &ri = temp;

l 在模板参数表中关键字class 和typename 的意义相同。然而,C++ 并不总是把 class 和 typename 视为等同的东西。有时你必须使用 typename。在你涉及到一个在 template(模板)中的 nested dependent type name(嵌套依赖类型名)的任何时候,你必须把单词 typename 放在紧挨着它的前面。"typename must precede nested dependent type names"(“typename 必须前置于嵌套依赖类型名”)规则的例外是 typename 不必前置于在一个 list of base classes(基类列表)中的或者在一个 member initialization list(成员初始化列表)中作为一个 base classes identifier(基类标识符)的 nested dependent type name(嵌套依赖类型名)。

l 函数对象与函数指针相比较有两个方面的优点:首先如果被重载的调用操作符是inline函数,则编译器能够执行内联编译提供可能的性能好处;其次函数对象可以拥有任意数目的额外数据,用这些数据可以缓冲结果,也可以缓冲有助于当前操作的数据。

l 静态数据成员可以被作为类成员函数的缺省实参而非static 成员不能。

l 也可以将成员函数声明为volatile限定修饰符。如果一个类对象的值可能被修改的方式是编译器无法控制或检测的,例如如果它是表示I/O 端口的数据结构,则把它声明为volatile,与const 类对象类似,对于一个volatile 类对象只有构造函数和析构函数,volatile成员函数可以被调用。

l union 不能有静态数据成员或是引用成员,如果一个类类型定义了构造函数,析构函数或拷贝赋值操作符,则它不能成为union 的成员类型。

l 匿名union 的数据成员可以在定义匿名union 的域中被直接访问。匿名union 去掉了一层成员访问操作符,因为union 的成员名可以像Token 类的成员一样被访问,所以匿名union 不能有私有或保护的成员,也不能定义成员函数。在全局域中定义的匿名union 必须被声明在未命名的名字空间中或者被声明为static。

l 名字空间别名的声明以关键字namespace 开头,后面是一个较短的别名,然后是赋值操作符,最后是原来的名字空间名。如果原来的名字空间名不是一个已知的名字空间名则会出现错误。

l 由于取地址操作符& 不能被应用在位域上所以也没有能指向类的位域的指针,位域也不能是类的静态成员,C++标准库提供了一个bitset 类模板它可以辅助操纵位的集合.在可能的情况下应尽可能使用它来取代位域

l 在类定义中用到的名字必须在使用前首先被声明。这个规则有两种例外的情况:第一个例外是对于被用在inline 成员函数定义中的名字,第二个例外是于被用作缺省实参的名字

l 如果针对指针类型的dynamic_cast失败,则dynamic_cast 的结果是0;如果针对引用类型的dynamic_cast 失败,则dynamic_cast会抛出一个异常。

l In general you use static_cast when you want to convert numeric data types such as enums to ints or ints to floats, and you are certain of the data types involved in the conversion. static_cast conversions are not as safe as dynamic_cast conversions, because static_cast does no run-time type check, while dynamic_cast does. A dynamic_cast to an ambiguous pointer will fail, while a static_cast returns as if nothing were wrong; this can be dangerous. Although dynamic_cast conversions are safer, dynamic_cast only works on pointers or references, and the run-time type check is an overhead.

l 当你要提供一个函数,其名称与继承而来的函数同名时,如果你不想因此遮掩了继承而来的函数,请以using declaration来突围。

l 和overload(重载)一样,所谓默认参数,系统根据物件的静态型别(static type)来决定。

l 当我们希望模塑出”is implemented in terms of”的关系,请选择membership/aggregation而不要使用inheritance。只有在绝对必要的情况下才使用private inheritance —— 也就是说当你需要存取protected members 或是需要改写虚拟函数时。绝对不要只为了重复运用程式码而是用public inheritance。

l Koenig Lookup: 如果你给函数提供一个class类型的实参(例如NamespaceA::ClassX类型的x),那么在名称搜索时,编译器将认为包含实参类型的命名空间中的同名函数为可选函数。

l void operator delete( void * );

void operator delete( void *, size_t );

Only one of the preceding two variants can be present for a given class. The first form works as described for global operator delete. The second form takes two arguments, the first of which is a pointer to the memory block to deallocate and the second of which is the number of bytes to deallocate. The second form is particularly useful when an operator delete function from a base class is used to delete an object of a derived class. The operator delete function is static; therefore, it cannot be virtual.

To call it as virtual, declare the destructor function as virtual.

l cout<<endl; 与 cout<<'\n';的区别是前者在输出换行符后更新输出流而后者只输出个换行符. 当然这个区别不是在所有的编译器中都有体现

l main()函数允许递归调用

l 在if语句里声明变量,1)只能是可转换为布耳型的变量2)只能在最开始申明不能放到括号里. 如if((int i=test())=0) ...; 错误 !

l 联合的初始化,只能对联合的第一个成员变量进行初始化,初始化值放在一对大括号中,只需要一个初始化值就够了,他的类型必须和联合的第一个成员相一致。

l 我们可以给指针变量任意的值,不过,要让它接受得费点事,在采用分段内存结构的计算机中编译程序时。如果程序的数据段和代码段是分开的,那么指向函数和指向数据的指针长度可以不一样

l The #line directive tells the preprocessor to change the compiler's internally stored line number and filename to a given line number and filename: #line digit-sequence ["filename"]

l SomeType t = u; 这是拷贝初始化。变量t通过SomeType的拷贝构造函数(Copy Constructor)被初始化。(注意,这条语句虽然含有“=”,但仍然是一个初始化操作,而不是一个赋值操作,因为在这里,允许使用’=’只是为了可以沿用C语言的语法,operator=是不会被调用的。)如果恰好也是SomeType类型,那么这条语句与”SomeType t(u);”是等同的,将调用SomeType的拷贝构造函数(Copy Constructor)。如果u是SomeType以外的其它类型,那么这条语句与”SomeType t(SomeType(u))”是等同的。可以看到,在语句”SomeType t(SomeType(u))”里,u被转换成一个临时的SomeType对象,而t则是由此拷贝构造出来的。注意在这种情况下,编译器通常可以(但不是必须要)对其进行优化,适当的处理拷贝构造(Copy Construction)操作(一般是省略掉拷贝构造过程)。如果进行了优化,则一定要保证拷贝构造函数(Copy Constructor)的可达性。

l Struct 默认public继承:class A{}; struct B:A{};

posted on 2007-07-01 17:15  套中人  阅读(199)  评论(0编辑  收藏  举报

导航