c++知识点(剑指offer题目)

来源:互联网 发布:unity3d虚拟仿真 编辑:程序博客网 时间:2024/06/05 19:00

博主记性不好,所以把要点记下来,方便以后复习。。。。

2017/7/14

【1】析构函数不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译器自动生成一个缺省的析构函数。

【2】给字符变量赋值,可以直接赋予字符 例:c = ‘c’,也可以用转义序列 例c = '72' c = '\x82' 默认为8进制,加上x为十六进制。

【3】现在new分配内存,失败时会抛出bad_alloc(位于new头文件中)异常,而不再是放回nullptr,需对异常进行处理,不然程序会异常终止。可以选择放回nullptr还是抛出异常。                                                          例:new (std::nothrow) int[100];new (std::newthrow) int[100];

【4】无论是protected、还是private继承,影响的只是外部对类成员的访问权限,派生类对基类的访问权限不会改变。

【5】异常处理:abort()不会释放内存直接退出程序,由系统回收。  exit()释放内存后退出程序。  处理格式 try{  throw DATA   }catch(...){   };    当异常没有被catch块捕捉时,程序会异常退出。c++PrimerPlus_P625

excetion异常类位于exception头文件中,logic_error(domain_error,invalid_argument...) 和 runtime_error(range_error,overflow_error...) 继承于exception类 位于stdexcetion头文件中。构造函数接收自定义的字符串,成员函数what()返回该元素。

2017/7/15

【6】异常规范:函数声明后加 throw(DATA) 例: void get() throw(int) 表示该函数不会抛出除int以外的异常类型。throw()表示不会抛出任何异常。如果抛出了指定以外的异常类型或者异常没有被catch捕捉处理,则程序会异常终止。catch块的接收类型的排列顺序应该与派生类的顺序相反。

【7】未捕获异常:当异常未被捕获时,将调用系统函数terminate(),其会调用abort()终止程序。可以通过set_terminate(FUNNAME)设置未捕获异常时执行的函数。在自定义的函数中要加入终止程序的代码例 exit();abort()否则会出错。

【8】意外异常:当抛出的异常没有在异常规范中时,将调用系统函数unexpected()其会调用terminate()进而调用abort()终止程序。可以通过设置set_unexpected(FUNNAME)调用自定义的处理函数、FUNNAME函数中如果抛出在异常规范中包含的异常(或者异常规范中有bad_execption类型,前提是要自定义函数)则旧异常会被新异常(或bad_exception)取代.如果新抛出的异常没有被catch接收仍然会导致程序终止。

【9】静态变量和全局变量都可以不用初始化,编译器会自动初始化。(定义静态变量的语句只执行一次)

2017/07/16

【10】派生类的对象/对象指针/对象引用可以赋值给基类的对象/对象指针/对象引用,基类的对象/对象指针/对象引用不能赋值给派生类的对象/对象指针/对象引用(基类引用和指针可以通过显式强制类型转换赋给派生类,而对象本身不能)。因为派生类包含了基类的所有信息,而基类缺乏派生类中的信息。

【11】静态变量在内存的静态存储区,静态数据一直占有着该存储区单元直到程序结束;静态局部变量只声明一次,一旦申请内存成功,不再接受重复申请。

2017/07/17

【12】dynamic_cast如果能安全的转换为目标类型指针时,则返回地址;否则返回空指针。当不能安全转换为目标类型引用时,由于不能放回空引用,所以会引发bad_cast异常(位于typeinfo头文件中)。需要对异常进行捕捉,否则程序会异常终止。注意:dynamic_cast不能对不含有虚函数的类型进行转换 P643

【13】typeid(OOP)放回type_info对象的引用;其中的name成员函数可以返回对象的信息。type_info重载了==符号,所以可以通过比较判断是否为同一类型的对象。但当OOP不能被识别时,如空指针,则会引发bad_typeid异常(位于typeinfo头文件中)。

【14】在使用RTTI时,应根据实际情况选择dynamic_cast或者typeid。

【15】 volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。

【16】const_cast主要用于const变量转化为普通变量(当然也可以由普通变量转化为const变量),对指针或者引用进行转换。用const_cast转化变量后修改其指向单元的值,输出后数据与修改前一样;主要原因是编译器对const变量进行了优化,在编译处理阶段对const变量进行了常量替换,而非对其数据单元进行取值操作。其实程序已经对该数据单元的数据进行了修改。P651

【17】static_cast只能转换原可以隐式互转的类型。如int->long long;double->float;int->double都是允许的。而不允许对不同类型的变量进行转换。

【18】reinterpret_cast对于无关类型的转换。详细请看P652

2017/07/18

【19】创建对象时加括号与不加括号的区别(有默认构造函数或构造函数有默认参数的情况下):在栈上创建对象时应该不加括号,加括号则为函数声明;并没有创建对象。在堆上创建变量时,加不加括号都会创建对象;加括号则为对象的数据成员初始化,不加括号则不初始化。

【20】函数声明后加const的作用:const对象只能调用const成员函数,const函数里只能调用const函数,并且不能对自身的数据成员进行修改,否则会编译错误。

【21】gets()会把\n读程序,并把\n换为\0;fgets()会读进\n。cin.getline()会抛去读进的\n,cin.get()会把\n留在输入流中。

2017/07/19

【22】内联函数必须在头文件中定义,因为内联函数在编译阶段会在调用的地方展开。当内联函数在资源文件中定义时,在编译程序时,会找不到次内联函数的定义。(新的编译器支持在资源文件中定义内联函数)

【23】对象数组,只有有默认构造函数或有默认参数构造函数的对象,可以创建对象数组;否则需要在创建数组时对对象数组进行初始化,否则会编译出错。

如有两个形参的构造函数   A a[2] = {{1, 2}, {3, 4} };    P368

2017/07/20

【24】string对象一开始会分配15个字节的内存,字符串占用的内存一旦超过分配的内存,则string对象会重新分配内存空间,在之前的基础上+16,以此类推。使用capacity()成员函数可以知道目前string对象分配的内存空间;使用reserve可以重新设置分配内存空间的大小(只能增大,如果指定的大小比原来小,则不进行任何操作[同样遵循+16的原则])。

2017/07/24

【25】智能指针模板(auto_ptr、unique_ptr、shard_ptr),因其构造函数采用了explicit,所以在使用时不能直接用常量指针,‘=’赋值,智能指针能在函数结束时自动删除指针指向的内存空间。auto与unique都是采用转移权限的方法,当一个指针指向同一内存空间时,第一个指向该内存空间的只能指针将被清除指向,把权限交给最后哦一个指向该内存空间的智能指针(避免函数结束时,释放两次内存导致程序异常终止)。而shard采用计数器的方式,每次指向+1,当计数器为1时才释放指向的内存空间。只有unique_ptr支持指向内存数组(delete[])。unique与auto的区别,当程序意图用两个智能指针指向同一内存时,auto会在运行期间出错,而unique会在编译阶段提出错误。在需要的情况下,可以用move函数给unique重新赋值;例:sp1 = move(sp2).unique_ptr和auto_ptr真的非常类似.其实你可以这样简单的理解,auto_ptr是可以说你随便赋值,但赋值完了之后原来的对象就不知不觉的报废.搞得你莫名其妙.而unique就干脆不让你可以随便去复制,赋值.如果实在想传个值就哪里,显式的说明内存转移std:move一下.然后这样传值完了之后,之前的对象也同样报废了.只不过整个move你让明显的知道这样操作后会导致之前的unique_ptr对象失效.

【26】sort和random_suffle要求数据结构支持随机访问。

【27】迭代器iterator、reverse_iterator、insert_iterator、front_insert_iterator、back_insert_iterator、istream_iterator<T> in(cin)、ostream_iterator<T> out(cout,"\n")迭代器介绍以及结合copy函数的使用;详见P687

【28】容器P695

2017/07/26

【29】clock() 这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick,毫秒)(宏定义在time.h中 CLOCK_PRE_SCE 1000);

【30】localtime(&time) time为time()返回的秒数,该函数返回一个tm类型的结构体指针。返回后应该马上取出内容,否则下一次调用此函数时,会覆盖掉之前的数据。

【31】对于unsigned整型溢出,C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”,也就是说,如果一个unsigned char(1字符,8bits)溢出了,会把溢出的值与256求模。对于signed类型,取决于编译器实现,一般来说如果不超过此类型的最大储存空间时,算到就是什么(补码),当超过时则会进行取模。

【32】函数对象可以使用类成员而不是函数参数来传递额外的信息。P707

【33】move_if(***) ***参数为一元谓词,如果放回true,则删除该元素。 

2017/07/28

【34】getch()和getche()是直接从键盘读取输入字符,getch()无回显,getche()有回显。getchar()则是从缓冲区读取字符。

【35】c++标准规定,对象的析构顺序和创建顺序相反。

【36】setvbuf()设置缓冲区地址以及大小,具体google。

2017/07/31

【37】函数适配器,bind1st()、bind2nd();例 bind1st(plus<int>(), 10)。把原是二元函数符转换为一元函数符。

2017/08/02

【38】枚举变量是全局变量的情况下, 枚举值的缺省值是0,不是枚举的第一个值(即使枚举值中没有0值)。 其他情况,其值是不定的,而且不限定于所列出的枚举值。

【39】MI虚继承

  1. class istream : public virtual ios  
  2. {  
  3.     //...  
  4. };  
  5.   
  6. class ostream : public virtual ios  
  7. {  
  8.     //...  
  9. };  
  10.   
  11. class iostream : public istream,public ostream  
  12. {  
  13.     //...  
  14. };  

【40】错误输出流 cerr和clog,默认输出流是屏幕。cerr无缓冲,而clog有缓冲。

2017/08/02

【41】枚举变量是全局变量的情况下, 枚举值的缺省值是0,不是枚举的第一个值(即使枚举值中没有0值)。 其他情况,其值是不定的,而且不限定于所列出的枚举值。

【42】(剑指offer)分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。

【43】cout.put() cout.write(char *, size) put()成员函数输出一个字符,write输出size个字符,并不受到空白符的影响。

【44】cout在输出显示浮点数时,当指数大于等于6或者小于等于-5时,采用科学计数法输出,否者采用定点表示法输出,类似于stdio库中%g(系统自行决定使用%f或%e输出)输出控制符。

【45】cout.width() 返回字段宽度的当前设置  cout.width(int) 设置字段宽度,并且返回以前的字段宽度。 width()方法值影响下一个项目,然后字段宽度恢复默认值。

【46】cout.fill(char) 设置字段宽度的填充的字符,默认为空格,对所有的输出语句都生效。

【47】cout.setf(ios_base::showpoint) 设置输出小数点后的0.  cout.presicion(int)设置输出的精度,位数不包括小数点包括整数和小数部分(默认模式下),在定点模式和科学模式下是小数点后的位置。

【48】setf()后并不会自动清除之前设置的标志,所用在设置进制等标志时,要使用set()第二个参数去清除之前的标志位ios_base::basefield  P748。

【49】showpoint和fixed的区别。fixed精度是小数点后,而showpoint精度是包含整数和小数部分。

iomanip的setw setprecision setfill功能与上述一样,只是可以用做标准控制符,方便编写程序。

2017/08/08

【50】输入异常。cin.rdstate返回流状态。clear(iostate)将清除其他异常位,设置当前异常位。setstate设置异常位,其他异常位不变。 exceptions()设置会引发异常的类型,clear设置流状态后会与exceptions返回值比较,如果其中某一位被设置则此位会引发异常ios_base::failure异常()。   P756

【51】当流状态被设置为异常时,后面的输入无法正常进行。需要重新清除位异常。

【52】isspace(char)判断字符是否为空白符。

【53】int cin.get()和istream & cin.get(char)  的区别:无参数方法返回读取字符的ascii码;当读取失败时返回EOF(-1)。有参数返回流对象;当读取失败时,返回false。

【54】istream &cin.ignore(int=1,int=eof) 例如ignore(255,'\n')读取并的丢弃接下来的n个字符或直到到达第一个换行符。

2017/08/09

【55】什么情况下设置failbit :getline在读取超过预定字符数时设置failbit,空行读取\n不会设置failbit,get在读取不到字符(空行)时设置failbit,在读取超过预定字符数时不设置failbit。

【56】istream的其他成员函数:  read(char ×,int)方法与getline一样,只是在读取字符串后不加\0,这样的设计是为了更好读取文件内容。char peek()返回下一个字符,但不抽取流中的字符。int count()返回最后一个非格式化抽取方法读取的字符个数。putback(char)在输入流前面插入一个字符。

【57】对文件的操作。seekg(int, ios_base::seekdir)   seekg(int)对输入流进行定位 seekp()对输出流进行定位   ios_base::end ios_base::beg ios_base::cut   tellg()  tellp()返回流的位置。 位置从0开始计算。

文件的写入  out.write(char *, int size).产生随机文件名(位于头文件cstdio)char * tempnam(char * pszname) 常量L_tempnam 文件名长度和 TMP_MAX 可以产生的文件名个数

785P

2017/09/18

函数参数默认值只能在函数声明或定义时指定,即二则只能选其一。

在类的声明中定义成员函数如果符合内联的条件则会成为内联函数,如果要将外联函数变为内联函数,需要在函数声明和定义前加inline关键字。

const和static一样作用域为当前文件,但static不能喝extern混用,const则可以。

变量引用只能引用变量,不能引用常量或者表达式以及类型不一致的变量。而常量引用可以引用常量,并且可以引用表达式或则类型不一致(但可以转化)的类型(会生成临时变量,相当于值传递)。

2017/10/16

当类有const数据成员时,编译器不会生成默认的赋值重载函数(我们可以自己写重载赋值函数,当不能在其中更改const变量的值)

==========================华丽的分割线===========================

以下是很久之前总结的了,记在doc里,没有时间。而且为了方便总结的好垃圾,现在自己看都觉得惨不忍睹。

=====================================================================

【58】 如果成员函数不在类体内定义,而在类体外定义,系统并不把它默认为内置(inline )函数,调用这些成员函数的过程和调用一般函数的过程是相同的。如果想将这些成员函数指定为内置函数,应当用inline作显式声明

【59】将引用参数声明为常量数据的引用的理由三个

使用const可以避免无意中修改数据的编程错误

使用const使函数能够处理const和非const实参,否则将只能接受非const数据

使用const引用使函数能够正确生成并使用临时变量

【60】返回值会创建一个临时变量,在被赋值后就被销毁,引用不产生临时变量

【61】临时变量在一个语句运行结束后销毁

【62】返回值会进行拷贝产生临时变量,而返回引用不存在拷贝

【63】传递类的对线参数的标准是按引用传递

【64】P275形参必须从右到左添加默认值

【65】P275从左到右给形参赋值,不能跳过

【66】函数原型即为函数声明(区别于函数定义)

【67】P275默认参数只需在函数原型中体现即可,不必在声明中体现(可有可无)

【68】P277函数重载:函数的特征标(参数类型,参数个数,参数名字、返回值并不是特征标)引用与值传递是同一个特征标,因为调用时不能区分调用那个函数。Const const也不能重载dawuconst int idawuint i)会报错

【69】非Const变量可以赋给const变量,但是const不能赋给非cosnt变量

【70】 Seekg tellg 第一个字符为0ios::end指向最后一个字符的下一个

【71】 emun 枚举 两个作用 a枚举变量 b元素常量(类似于宏定义)

【72】不可将整形赋给枚举类型(不会进行隐式转换)要显示转换

【73】枚举元素的作用域是上一个代码块,因此同一作用域中不能定义相同的枚举元素

【74】const成员或引用类型的成员。因为const对象或引用类型只能初始化,不能对他们赋值。 

【75】当打开一个文件时,文件指针位置为0,并不是指向第一个字符,即第一个字符的位置为1。这一点我们可以通过peek()函数验证。peek()返回的是当前文件指针下一个位置的字符。

【76】 Eof文件结束符是读取错误产生的,并不是在文件中的。EOF的值可能就是所要处理的二进制文件中的信息。这就出现了需要读入有用数据却被处理为文件结束的情况。为了解决这个问题,C提供了一个feof()函数,可以用它来判断文件是否结束。feoffp)用于测试fp所指向的文件的当前状态是否为文件结束。如果是,函数则返回的值是1(真),否则为0(假)。流指针指向读取完字符的下一个位置,所以指针指向eof时,需要再读取一次,feof才会是true

【77】返回类型不同不算重载

【78】Static无论是局部还是全局静态变量都在查询运行时分配内存空间,全局在函数开始时初始化。多次调用函数时,局部则初始化只执行一次。

【79】c语言中const会分配内存空间,而c++中不会等同于#define替换,但是当用extern修饰时,则会分配内存空间。

【80】 枚举和define的区别,define在编译之前进行替换,预处理。而枚举在编译期间进行替换。可以理解为编译阶段的宏。(enum和const更为类似)实际上是int形(4个字节)

【81】p412 static const待理解

【82】 常量成员函数声明:如:int get() const;

规则:

1.常量成员函数不修改对象。

2.常量成员函数在定义和声明中都应加const限定

3.非常量成员函数不能被常量成员函数调用,但构造函数和析构函数除外。

4.常量(const对象)对象只能调用常量成员函数。(const对象的数据成员在对象寿命周期内不能改变,因此其只能调用常量成员函数)。

意义:

1.使成员函数的意义更加清楚,将成员函数分修改对象和不修改对象两类。

2.增加程序的健壮性,常量成员函数企图修改数据成员或调用非常量成员函数,编译器会指出错误。

原因:

     对于X类型的非常量成员函数而言,其this指针的类型是 X * const,该指针自身是常量;但是对于X类型的常量成员函数而言,其this指针的类型是const X * const,是一个常量指针。

【83】Extern “C” void dawu();c语言连接性(用c语言编译的函数名称修饰不一样,需要指出)

【84】 Extern “C++” void dawu();

【85】Const修饰的变量是内部链接性,要变成外部链接性的话,要用extern声明,外部引用全部都要区别于常规变量(定义时不用extern)

【86】Const对象只能调用const成员函数

【87】Const成员函数只能改变static,不能改变成员函数

【88】 c++11标准允许在类声明中初始化变量【static变量除外】(重要),而c99标准只允许在初始化列表中初始化。

【89】在类中定义的结构体或枚举,如果为公有则类外部可以使用作用域解析符,如果为私有,则不允许访问。

【90】 成员初始化列表会覆盖类内的初始化。

【91】Vector 内存分配,dev每次分配之前的2倍,vs每次分配之前的3/2

【92】String 内存分配,vs一开始分配15,后面每一次增加16

【93】重载区分const,不区分引用

class C

{

    void f(int i);

    void f(const  int i);

};

这个是错误的,编译通不过。那么是不是说明内部参数的const不予重载呢?

再看下面的例子:

class D

{

public:

    void f(int &i) { std::cout<<"3";}; //函数3;

    void f(const  int &i){ std::cout<<"4" ;};//函数4

};

 这个程序是正确的,看来上面的结论是错误的。为什么会这样呢?这要涉及到

接口的透明度问题。按值传递时,对用户而言,这是透明的,用户不知道函数对形参

做了什么手脚,在这种情况下进行重载是没有意义的,所以规定不能重载!当指针或
引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载
是有意义的,所以规定可以重载。

引用被引入时,用户就会对函数的操作有了一定的了解,不再是透明的了,这时重载

是有意义的,所以规定可以重载。

【94】Gets把\n换成\0

Fgets会读入\n

Puts输出会自动换行

【95】运算优先级

左结合 -> []

右结合 *

       ++ --

+ - / *

&&

& |

【96】类的转换函数

必须为类的成员函数 operator int(){ return this->data }

无返回值 无参数以对象来调用转换函数

 

【97】Void parent::f(const char * a)这里const保证a不被修改

Void parent::f()const{}这里const保证不修改调用此函数的对象 parent-+

 

【98】如果是隐式继承(保护继承),则派生类引用转化为基类需要显示转换。(可以访问基类的成员)不受私有继承的影响

【99】可以在派生类中可以使用using 声明使用基类的公共函数(私有继承和保护继承下)【public和protected的成员】

【100】定位new运算符

New (address) type【number】

【101】多重继承(MI)

1.虚继承初始化同父类时要直接调用基类的构造函数(因为有两条路径上传到父类产生二义性)2.要用作用域解析符来调用基类的成员方法(因为不知道调用哪一个基类的方法)

 

【102】Template

模板信息必须都放在同一文件中(声明和实现,不能分开放)因为只是其只是模板并不能单独编译。

类模板在使用时必须指定类型,而模板函数在调用时有时候可以省略类型名(编译器可以根据类型自动生成)

非类型参数non-type 只能为整形,指针,枚举,引用

在不产生二义性的前提下模板函数可以省略类型参数,产生二义性则必须加类型参数说明

可以给类模板类型参数加默认值,但是不能给函数模板类型参数加默认值,可以给非类型参数加默认值

 

 

【103】内联函数和模板函数一样。实现要放在头文件,不能放在头文件中,因为其为内部链接性

 

(1) 在一个文件中定义的内联函数不能在另一个文件中使用。它们通常放在头文件中共享。
2) 内联函数应该简洁,只有几个语句,如果语句较多,不适合于定义为内联函数。 
3) 内联函数体中,不能有循环语句、if语句或switch语句,否则,函数定义时即使有inline关键字,编译器也会把该函数作为非内联函数处理。
4) 内联函数要在函数被调用之前声明。


【104】在创建对象时赋值,是调用拷贝构造函数,而不是赋值构造函数

【105】数组作为函数的参数是会退化为函数指针的,想想看,数组作为函数参数的时候经常是需要传递数组大小的

【106】结构体大小取决于两分方面

偏移量必须为成员的整数倍结构体大小必须为成员的整数倍

 

【107】初始化时a【2】【2】 = {{1},{2}} 结果 1,0,2,0

a【12】  a和&a不一样

【108】Double marm() Noexcept 明确程序无异常

 

【109】异常处理

Abort()直接退出程序,不释放内存

Exit()释放内存后退出

Try

{

Throw data

}

Catch(...)

{

 

}

 

【110】现在new分配内存,失败时会抛出异常,而不再是放回nullptr,需对异常进行处理,不然程序会异常终止。可以选择放回nullptr还是跑出异常

New (std::nothrow) int【100】

New (std::std::nowthrow) int【100】

【111】Private继承 派生类也能直接访问基类成员。只对外部有访问影响

 【112】析构函数不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译器   自动生成一个缺省的析构函数


2017/11/03

【113】在case作用域中,如果要初始化变量,需要加上{}

2017/11/20【114】 数组成员是不能在初始化列表里初始化的,不能给数组指定明显的初始化。  或许有人问,以上几条似乎有冲突喔!一个类中能不能定义常量数组?如:const int aa[100];如果可以,怎么初始化aa?  实际上不行的。我们可以用static数据成员来解决此问题。

【115】c++运行在类定义的时候进行初始化数据成员

【116】函数void f(int)的函数指针: void(*Fun)(int)

【117】数组指针   int a[10]; int (*ap);   int b[2][2]; int(*bp)[2];  http://blog.csdn.net/touch_2011/article/details/6966980


原创粉丝点击