ccyy's coding zone
往前走,不要留恋路边的风景.
posts - 25,comments - 9,trackbacks - 0
    这段时间扫了C++Primer,自己觉得比较有用的tips,仅作为自己参考...

 

1.如果要在多个变量中使用一个const变量,可以在一个头文件中定义,然后再其他文件中include<>
  或者可以在c++的源文件中定义,然后才其他源文件中extern 

2.标准头文件用#inclue<>
   自定义的头文件用 #include “”

3.预防多次包含偶同一头文件
  #ifndef  SALE
 #define  SALE //表示接受一个名字并定义该名字为预处理器变量
  //....
   define of class and relate function
  #endif

4.迭代器iterator的begin()操作返回的迭代器容器的第一个元素,end()返回容器的迭代器指向容器最后一个元素的下一个元素

5.如果不改变容器的内容,只做读操作,使用const_iterator,
区别于const 的iterator,声明一个const 迭代器,必须初始化,且一旦初始化后就不能改变。

6.迭代器的算术操作
iter + n 产生一个新的迭代器,位置指向iter指向元素之后n各的位置
iter1 - ite4r2 返回两个迭代器对象的距离

7.任何改变vector长度的操作都会使已存在的迭代器失效,如push_back

8.指针的初始化
0
类型匹配的对象的地址
另一对象之后的下一地址
同类型的另一个有效指针

9.void* 指针可以保存任何对象的地址
表明指针只与一个地址相关,并不知道地址上所存的对象类型,不能用 void *操纵它所指的对象

10. #include <cstddef>
size_t unsigned 用来指明数组的长度
ptrdiff_t unsigned  用来指明指针的距离

11
指向const对象的指针
const double * cptr;
并不是指针本身是const的,而是所指的对象是const的,不能通过cptr修改所指对象的值,也不能把const对象的地址赋值给非const指针,

const 指针
int *const p = &num;
必须在定义时初始化。

指向const 对象的const 指针
const double *const ptr = &pi;

12.string .c_str()返回const char 类型的指针


13sizeof返回size_t类型,计算数组元素的个数
 n = sizeof(arr)/sizeof(*arr);

14.算术转换
int + double -> double
float + double -> double
int = double -> int
float = double -> float
chat + float -> float
short + long -> long
int + unsigned long -> unsigned long

15 强制类型转换
const_cast<>()转换掉表达式的const性质
static_cast<>()很适合将一个较大的类型转换成一个较小的类型。

16.函数的参数
int fun(int *p) 可以改变指针所指的对象的值

int fun(int *p) 如果保护指针所指的参数的值,要加上const  int f(const int *p)

void fun(const int i) 不能改变实参的的局部副本,can read but can't write to i ;

17 引用
引用形参直接关联到所绑定的对象.void swap(int &a , int &b)

像函数传递大型对象的时候,利用const引用避免复制,

复制庞大而复杂的值有昂贵的开销。为了避免传递副本的开销,可将形参指定为引用类型。对引用形参的任何修改会直接影响实参本身。应将不需要修改相应实参的引用形参定义为 const 引用

非const引用的形参只能与同类型的非const的对象关联.
18 数组形参的定义
void f (int *)
void f (int [])
void f (int [10])
以上三种都等价为 void f(int *)

19 通过引用传递数组
void f(int (&arr)[100])
传递的是数组的引用本身,数组大小成为形参和实参的一部分,编译器会检查两者是否匹配。

29返回值
返回非引用类型,函数会在调用出将函数返回值复制给临时对象。
返回引用返回的是对象本身,不要返回局部对象的引用
   const string &f(const string & s)
  {   string ret = s; return ret ;}//err
不要返回指向局部对象的指针(悬垂指针)

30默认实参
string ScreenInit(string::size_type with = 24 ,string::size_type heigth = 59 );
string screen = ScreenInit();
screen = ScreenInit(20)
screen = ScreenInit(20,90)


40将函数指定为内联是建议编译器在调用点直接把函数代码展开,内联函数避免函数调用的开销,内联函数必须在头文件中定义,


41const成员函数,在参数列表后面加上const ,则const成员函数不能改变调用该函数的对象。

42在局部声明的变量名字将屏蔽在全局生命的同名名字,这个性质对函数名也同样成立。

43.函数指针
bool (*pf)(const string &, const string &); 
typedef bool (*cmpFcn)(const string &, const string &); 
圆括号不可以省略。 
函数指针只能通过同类型的函数或函数指针或 0 值常量表达式进行初始化或赋值

44.IO对象
IO对象不可复制或赋值,不可以存在vector等容器中.

形参或返回类型也不能为流类型。如果需要传递或返回 IO 对象,则必须传递或返回指向该对象的指针或引用  

 ofstream &print(ofstream&); 

45.输出缓冲区的管理
统将字符串字面值存储在与流 os 关联的缓冲区中。下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件

  1. 程序正常结束。作为 main 返回工作的一部分,将清空所有输出缓冲区。

  2. 在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新。

  3. 用操纵符显式地刷新缓冲区,例如行结束符 endl

  4. 在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区。

  5. 可将输出流与输入流关联(tie)起来。在这种情况下,在读输入流时将刷新其关联的输出缓冲区。
    cout << "hi!" << flush;      // flushes the buffer; adds no data     
    cout << "hi!" << ends;       // inserts a null, then flushes the buffer     
    cout << "hi!" << endl;       // inserts a newline, then flushes the buffer

    unitbuf 操纵符。这个操纵符在每次执行完写操作后都刷新流:

        cout << unitbuf << "first" << " second" << nounitbuf; 
    当输入流与输出流绑在一起时,任何读输入流的尝试都将首先刷新其输出流关联的缓冲区。标准库将cout 与 cin 绑在一起,因此语句:cin >> ival;导致 cout 关联的缓冲区被刷新。


46stringstream 可将多种数据格式与string类型进行自动转化

47成员函数:
在类内部定义的函数默认为inline.
将关键字const加在形参列表之后,const成员函数不能改变其所操作对象的数据成员。

48const成员函数返回*this
普通非const成员函数的this是一个指向类类型的const指针,可以改变this指向的值,不能改变this所保存的地址,而const成员函数,this的类型是一个指向const类型对象的const指针。const成员函数只能返回*this作为const 引用,

50mutable数据成员
将类成员声明为mutable,任意const对象,或者const函数丢可以改变它的值

51构造函数
不管成员是否在构造函数中显示初始化,类类型的数据成员总是在初始化阶段初始化。在构造函数初始化列表没有显示提及的每个成员,运行该类型的默认构造函数,内置货符合类型的初始值依赖于对象的作用域:在局部作用域这些函数不被初始化,在全局作用域被初始化为0.
没有默认构造函数的类类型成员,以及const或引用类型的成员,都必须在初始化列表进行初始化。
按照与声明一致的次序编写构造函数初始化列表是个好主意。

52默认构造函数
定义一个对象是没有提供初始化式,就是使用默认构造函数,为所有形参提供默认实参的构造函数也定义了默认构造函数

53static成员和成员函数 
非static成员存在于每个类类型的对象中,而static成员独立于该类的任意对象而存在,美国各static数据成员是与该类关联的对象。
static成员函数没有this形参,可以直接访问所属类的static成员,但是不能直接使用费static成员

54复制构造函数
复制构造函数只有一个形参,该形参(常用const修饰)是对该类类型的引用,当定义一个新对象并用一个同类型的对象对他进行初始化的时候,是显式得使用复制构造函数,将该类型的对象传递给函数uo从函数返回该类型的对象的时候,是隐式得使用复制构造函数。
string null_book = "9-999-99999-9"; // copy-initialization      
string dots(10, '.');               // direct-initialization      
string empty_copy = string();       // copy-initialization      
string empty_direct;                // direct-initializat

 55为了避免复制,类必须显式声明复制构造函数为private
然而这样类的友元和成员仍可以复制,如果要连友元和成员的复制也禁止,可以定义一个private的复制构造函数但不对其定义。

56赋值操作符重载
当操作符为成员函数的时候,第一个操作数隐式地绑定到this指针,即this绑定到左操作数的指针,右操作数一般为const传递的引用,复制操作返回同一类型的引用。

57析构函数
析构函数没有参数也不能重载,即使我们编写了自己的析构函数,合成析构函数仍然运行,合成析构函数不删除指针成员所指向的对象,合成析构函数按对象创建的时间逆序撤销每个非static成员。

58重载操作符
赋值(=)、下标([])、调用(())和成员访问箭头(->)等操作符必须定义为成员,将这些操作符定义为非成员函数将在编译时标记为错误
复合赋值操作通常定义为类的成员,但不一定要定义成类的成员
改变对象状态或与给定类型紧密联系的操作,如自增,自减和解引用操作,都应该定义为类的成员
对称的操作符,如算术操作符,相等操作度关系操作符和类操作符,最好定义为普通非成员函数
IO操作必须为非成员函数
赋值必须返回对*this的引用
operator + 返回一个对象,而operator +=返回一个引用
定义下标操作符[]时,一般定义两个版本,一个为非const成员返回引用,另一个为const成员返回const引用。
class S
{
    public :
          int &operator[] (const size_t);
          const int &operator[]( const size_t)const;
}

59定义转换和操作符
(1)不要定义相互转换的类,机如果类Foo具有接受类 Bar的对象的构造函数,不要再为类Bar定义到类型Foo的构造函数
(2)避免到内置算术类型的转换,具体而言,如果定义到算术类型的转换,不要定义接受算术类型的操作符的重载版本,如果用户需要使用这些操作符,转换操作副将转换你所定义的类型的对象,然后可以使用内置操作符
不要定义转换到一个以上算术类型的转换,让标准抓包换提供到其他算术类型的转换

60基类成员函数
成员函数默认为非虚函数,对f非虚函数的调用在编译时确定,除了构造函数,其他非static成员函数都可以是虚函数,虚函数运行时动态绑定,

61访问控制和继承
public private和protect
用户可以访问类的public成员,不能访问private成员
private成员只能由基类的成员或友元访问
派生类对象对基类的public和private成员的访问权限和程序中任意其他部分一样,可以访问public不能访问private。
protect成员不能被类的用户访问,可以被类的派生类访问,派生类只能通过派生类的对象访问基类的protect成员,派生类对基类类型对象的proteced成员没有访问权限

62虚函数动态绑定
出发动态绑定的两个条件:1.指定为virtual,2,必须通过基类类型的引用或指针进行调用

63派生类虚函数调用基类版本的时候,必须显式使用作用域操作符

64虚函数的基类版本和派生类版本使用不同的默认实参,通过基类的指针或引用调用,但实际执行的是派生类的版的时候会出问题,因为虚函数基类版本定义的默认实参会传给派生类的版本。

65pubilc,private,和protect继承
public inheritance :基类的public成员为派生类的public成员,基类的protect成员为派生类的protect成员
private inheritance:基类的所有成员在派生类中为private成员
protect inheritance:基类的public成员和protect成员在派生类中为protect成员
派生类不能访问基类的protect成员
类的默认的继承为private,struct默认的继承为public的

65继承和static成员
如果基类定义了static成员,则整个继承层次中只有一个这样的成员,无论基类派生出多少个派生类,没个static成员只有一个实例

66派生类到基类的转换
可以用派生类的对象对基类对象进行赋值或初始化
引用转换不同于转换对象,将派生类对象传给希望接受基类对象的函数是,该派生类对象的基类部分被复制到形参

67从基类到派生类的自动转换时不存在的

68如果派生类显示定义复制构造函数或赋值操作符,则该定义将完全覆盖默认定义,必须显示的调用继承的复制构造函数和赋值操作符对基类成分以及类自己的成员进行复制或赋值。
class Derived{
   public: 
        Derived(const derived &d):Base(d) { other menber initialization}
}

69即使没有工作要做,继承层次的跟类也应该定义一个虚析构函数

70构造函数不能是虚函数,复制操作符最好不要是虚函数(虚函数的形参列表等必须相同,会引起混淆)

71如果在构造函数或者析构函数效用虚函数,则调用的是为构造函数或析构函数自身类型定义的版本。

72与基类成员同名的派生类成员将屏蔽对基类成员的直接访问,成员函数名也一样。

73重载成员函数
如果派生类定义了重载成员函数,则通过派生类类型之unengfangwen派生类中重定义的那些成员,如果要访问,加个using声明(?)

74容器与继承
如果定义了一个基类类型的容器,派生类对象在赋值给容器的时候,对象的派生属性会被切掉,只保留基类的成分

75c++继承如火确定函数调用
1.

首先确定进行函数调用的对象、引用或指针的静态类型。
2.

在该类中查找函数,如果找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。如果不能在类或其相关基类中找到该名字,则调用是错误的。
3.

一旦找到了该名字,就进行常规类型检查,查看如果给定找到的定义,该函数调用是否合法。
4.

假定函数调用合法,编译器就生成代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则,编译器生成代码直接调用函数。

76模板
模板形参是const引用
函数体中的测试之用 < 比较
多个类型形参的实参必须完全匹配 

77异常
异常通过抛出(throw)对象引发,执行throw的时候,不会执行在throw后面的语句,而是将控制从throw转移到匹配的chatch。
处理异常的时候会四方局部存储,被抛出的对象不能再局部存储,而是用tw表达式出事话一个床位异常对象的特殊对象。
当抛出一个表达式的时候,被抛出的对象的静态编译时的类型将决定异常对象的类型,最好不要抛出指针
当catch结束的时候,在紧接在与该try块相关的最后一个cahtch子句只有的点继续执行
一个快可以通过调用new动态分配内存,如果该块因异常退出,编译器不会删除该指针,已分配的内存将不会释放。
在查找匹配的catch期间,不是寻找最佳匹配,而是选中第一个找到的可以处理该异常的cahtch
如果被抛出的对象是派生类类型的,但由接受基类类型的catch处理,cahtch将不能使用派生类特有的所有成员,所以cahtch子句处理因继承而相关的类型的异常,它就应该将自己的形参定义为引用。
重新抛出throw,当catch无法处理的时候,将重新抛出throw将异常传递给函数调用链中更上层的函数
exception类所地被你故意的唯一操作时一个名为what的虚成员,该函数返回,const char*
可能存在异常的程序以及分配资源的程序应该使用类来管理那些资源,如果函数因异常而提早退出,编译器就运行类的析构函数最为异常处理过程的一部分。

77auto_ptr
为异常安全的内存分配使用auto_ptr,
当复制auto_ptr对象或者将它的值付给其他arto_por对象的时候,将基础对象的所有权从原来的auto_ptr对象传给副本,原来的auto_ptr对象重置为未绑定状态
赋值操作删除做操作数指向的对象
应该只用get询问auto_ptr对象或者使用返回的指针值,不能用get作为创建其他auto_ptr的实参
调用auto_ptr的reset的时候,会删除auto_ptr所指向的对象。
不要使用两个auto_ptr指向同一对象,不要使用auto保存对象保存指向动态分配数组的指针,以为当auto_ptr被删除的时候,它使用的是delete操作符,不是delete[]

78c++内存分配方式
(1)allocator 类
(2)标准库中的oprator new和operator delete函数

79new operator(primerl里面成为operator new 函数)  operator new 和placement new
new operator :
(1)string *sp = new string("abc");
1.先调用operator new 的标准库函数分配足够大的原始的为类型化的内存2.以保存指定内存的一个对象;运行该类型的一个构造函数,用指定初始化式构造对象,3.返回指向新分配内存并构造的指针。
(2)operator new:
void *operator new(size_t)
void *operator new[](size_t)
获得未构造的内存
operator detete不会调用析构函数,只会释放指定内存
(3)placement new:(定位new)
new (place_address)type
place_address为一个指针,

80运行类型识别(RTTI)
(1)typeid操作符,返回指针或引用类型所致对象的实际类型
base *pb;
derived *pd;
if(typeid(*pb) == typeid(*pd))
{
   //测试对象动态类型
}
if(typeid(pb) == typed(pd))
{
  //测试指针的静态编译的类型,永远不等
}
(2)dynamic_cast操作符,将基类类型的指针或引用安全转化为派生类类型的指针或引用
dynamic_cast<*derived>(BasePtr)
81类成员函数指针和成员指针
类数据成员指针定义:
 类型 类名::* name
成员函数指针定义
返回类型 (类名::指针名 *)(形参列表)

82volatile限定符 

直接处理硬件的程序常具有这样的数据成员,它们的值由程序本身直接控制之外的过程所控制。例如,程序可以包含由系统时钟更新的变量。当可以用编译器的控制或检测之外的方式改变对象值的时候,应该将对象声明为 volatile。关键字 volatile 是给编译器的指示,指出对这样的对象不应该执行优化。

posted on 2011-07-31 19:00 ccyy 阅读(307) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理