精华内容
下载资源
问答
  • C++重点知识点总结及习题
  • C++重点知识点总结及习题,
  • 本文档中总结出来了C++的所有重要的知识点,很适合复习C++的基础知识。
  • C++重点知识点清单

    2017-10-02 10:46:12
    学习c++之后,通过知识点清单可以将这门语言通过清单的形式总结出来,有利于初学者能快速掌握C++必备知识点,为写代码打下良好基础。
  • C++知识点总结

    2018-11-08 13:51:28
    C是一个结构化语言,如谭老爷子所说:它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何...

    C与C++的区别

    引用别人说的一段话

    C是一个结构化语言,如谭老爷子所说:它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 所以C与C++的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C++比C更先进,是因为“ 设计这个概念已经被融入到C++之中
    ”,而就语言本身而言,在C中更多的是算法的概念。那么是不是C就不重要了,错!算法是程序设计的基础,好的设计如果没有好的算法,一样不行。而且,“C加上好的设计”也能写出非常好的东西。
    对语言本身而言,C是C++的子集,那么是什么样的一个子集?从上文可以看出,
    C实现了C++中过程化控制及其它相关功能,而在C++中的C(我称它为“C+”),相对于原来的C还有所加强,引入了重载、内联函数、异常处理等等玩艺儿,C++更是拓展了面向对象设计的内容,如类、继承、虚函数、模板和包容器类等等。
    再提高一点,在C++中,数据封装、类型这些东东已不是什么新鲜事了,需要考虑的是诸如:对象粒度的选择、对象接口的设计和继承、组合与继承的使用等等问题。
    所以相对于C,C++包含了更丰富的“设计”的概念,但C是C++的一个自洽子集,也具有强大的功能,同样值得学习。

    C真是C++的子集吗?

    C 是 C++ 的子集吗?
    严格按照数学上的定义来说,C 不是 C++ 的子集。有些程序在 C 里面是合法的,但在 C++ 里却是不合法的;甚至有些编写代码的方式在 C 和 C++ 中有不同的含义。然而,C++ 支持 C 所支持的全部编程技巧。任何 C 程序都能被 C++ 用基本相同的方法写出来,并且运行效率和空间效率都一样。把数万行 ANSI C 代码转换成 C 风格的 C++ 代码,通常只需要几个小时。因此,C++ 是 ANSI C 的超集程度和 ANSI C 是 K&R C 的超集程度以及 ISO C++ 是 1985 年的 C++ 的超集程度差不多。
    编写风格好的 C 程序通常会是合法的 C++ 程序。例如,Kernighan 和 Ritchie 合著的《C 程序设计语言(第二版)》中的所有例子都是 C++ 程序。
    C/C++ 兼容性问题的一些例子:

    int main() 
    { 
    double sq2 = sqrt(2); /* 不是 C++:调用了未经声明的函数 */ 
    int s = sizeof('a'); /* 隐蔽的区别:C++ 中是 1,而 C 中却是 sizeof(int) */ 
    }
    

    调用未经声明的函数在 C 里是不良风格,而在 C++ 里是非法的。同样的情况还有,传递参数给一个没有在其声明中列出参数类型的函数:

    void f(); /* 没有注明参数类型 */
    void g() 
    { 
    f(2); /* C 中是不良风格。C++ 中不合法 */ 
    }
    

    C 里面,void* 可以隐式转换为任何指针类型,并且堆空间分配通常是通过 malloc() 进行的,无法检查是否已经分配了足够的内存:

    void* malloc(size_t);
    void f(int n) 
    { 
    int* p = malloc(n*sizeof(char)); /* C++ 中非法。C++ 使用 new 分配堆空间 */ 
    char c; 
    void* pv = &c; 
    int* pi = pv; /* 隐式转换 void* 为 int*。C++ 中非法 */ 
    }
    

    请注意,隐式转换 void* 为 int* 引起了潜在的数据对齐错误。请参阅 C++ 中 void* 和 malloc() 的代替品。
    把 C 代码转换成 C++ 时,请紧记 C++ 的关键字比 C 多:

    int class = 2; /* C 中合法。C++ 中是语法错误 */ 
    int virtual = 3; /* C 中合法。C++ 中是语法错误 */
    

    除了少数例外,如上面所述的例子(以及 C++ 标准和 C++ 程序设计语言第三版附录 B 里详细列举的例子),C++ 是 C 的超集。(附录 B 可以通过下载获取)
    请注意,“C”在以上段落中指的是经典 C 和 C89。C++ 不是 C99 的后裔;C++ 和 C99 是兄弟。C99 引入了一些新特性,造成 C/C++ 的不兼容性进一步增大。这里有一篇 C++98 和 C99 的不同点的描述。

    =========================================================
    以上摘自Bjarne Stroustrup’s FAQ(中文版)

    另外,C++兼容C89的标准,不完全兼容C99标准。

    一些C++的概念

    • 函数模板:“雪糕模子”,倒入不同的原料,可以产出不同的雪糕。一个模板用于函数体相同,参数的个数相同但类型不同的情况。参数的个数不同是则不能使用函数模板。
    • 多态:字面的意思“多种状态”。它是一些函数名字相同的函数的不同的状态。亦或者说不同功能的函数可以使用相同的函数名,参数或者类型不同。就比如一个函数叫“买东西”,而买什么东西,数量,颜色等等性质,由参数传入,就可以是买水果,买菜,买零食等等。
    • 函数重载:重载的本质是重新定义了一个函数,虽然函数名相同,但它们编译后的名字和函数的入口地址是不同的。参数的个数和类型至少有一项不同,只有函数类型不同是不可以使用函数重载的。
    • 默认参数:传递给函数的参数按照从左至右的顺序与形参结合,所以指定默认参数必须从最右边开始。
    • 默认构造函数:调用默认构造函数时不必给出实参,所以指定了所有参数默认值的构造函数也是默认构造函数。类的构造函数有且只有一个。
    • 后续补充…
    展开全文
  • C++超强的知识点总结

    2011-03-07 13:49:22
    对学习C++有很大的帮助,里面包含了C++中的几乎所有的重点难点知识,对面试或学习都会很有帮助的
  • 自己整理的山东大学C++考试重点 自己整理的山东大学C++考试重点 自己整理的山东大学C++考试重点
  • c++在c的基础上增添类,C是一个结构化语言,面向过程,它的重点在于算法,即通过一个过程将输入量经过各种运算后得到一个输出;而C++是一种面向对象的语言,首要考虑的是如何构造一个对象模型,这样就可以通过获取...

    一、语言比较

    1. C和C++的区别

    c++在c的基础上增添类,C是一个结构化语言,面向过程,它的重点在于算法,即通过一个过程将输入量经过各种运算后得到一个输出;而C++是一种面向对象的语言,首要考虑的是如何构造一个对象模型,这样就可以通过获取对象的状态信息得到输出。

    2. C++和python的区别:

    python是一种脚本语言,是解释执行的,不需要经过编译,所以很方便快捷,且能够很好地跨平台,写一些小工具小程序特别合适。而C++则是一种需要编译后运行语言,在特定的机器上编译成机器码执行,运行效率高,安全稳定。但编译后的程序一般是不跨平台的。

    注:java既可以是解释执行也可以是编译执行

    3. C++是不是类型安全的?

    不是。两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。

    4. C++的类和C里面的struct有什么区别:

    (1)C++类中属性默认访问类型为private,而c中的struct默认的访问类型为public

    (2)c++类可以有继承,虚函数,多态,而c中struct不可以。C语言struct里面不可以有函数,只能有变量。 C++给C中的struct功能扩展了(多了面向对象)

    5. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?

    C用宏定义,C++用inline。

    带参数的宏和内联函数的区别
    内联函数的执行过程与带参数宏定义很相似,但参数的处理不同。带参数的宏定义并不对参数进行运算,而是直接替换;内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算求值,然后把表达式的值传递给形式参数。内联函数与带参数宏定义的另一个区别是,内联函数的参数类型和返回值类型在声明中都有明确的指定;而带参数宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患。
     
    先说宏和函数的区别:
    1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型.
    2. 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.
    3. 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的.因此,宏占用的是编译的时间,而函数占用的是执行时的时间.
    4. 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的.
    5. 函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的.
     
     现在来看内联函数:
    所谓"内联函数"就是将很简单的函数"内嵌"到调用他的程序代码中,只样做的目的是为了避免上面说到的第5点,目的旨在节约下原本函数调用时的时空开销.但必须注意的是:作为内联函数,函数体必须十分简单,不能含有循环、条件、选择等复杂的结构,否则就不能做为内联函数了。事实上,即便你没有指定函数为内联函数,有的编译系统也会自动将很简单的函数作为内联函数处理;而对于复杂的函数,即便你指定他为内联函数,系统也不会理会的。

    6. 结构体和枚举的区别

    结构体一般是把同一个事物的各种属性封装在一起(就是说各个变量的类型可以是不同的),而枚举一般是把具有共同属性的事物封装在一起(属性相同,变量类型就是要一样的)。

    共同点是他们都只能封装变量而不能封装函数。

    7. 结构体与联合体有何区别?

    (1)结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。

    (2)对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。

    8. main函数执行之前,还会执行什么代码?

    全局对象的构造函数会在main函数之前执行。

    二、内存

    1. C++的内存管理机制:

    操作系统为C++分配的内存分成4个区,分别是堆(动态申请数据)、栈(局部变量)、静态数据区(全局/静态变量)和代码区(程序代码)。

    2. 堆和栈的区别:

    (1)内存:栈区存放局部变量和函数参数等,由编译器自动分配释放,申请速度快;堆区存放动态数据,由程序员人工分配释放,自己申请的时候要指明大小,申请速度较慢。

    申请后系统的响应:

    栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

    (2)数据结构:栈先进后出;堆通常指二叉堆,是一个经过排序的完全二叉树,特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。以数组的形式实现,这样就可以方便的读取每一个成员节点。

    3. 堆栈溢出的原因:

    栈溢出:数组越界或者函数内局部变量使用过多。堆溢出:可能是程序员申请了资源但是忘记释放了。

    4. 内存泄漏:

    一般来说有两种情况。一种情况如在C/C++ 语言中的,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。

    第一种情况,在 Java 中已经由于垃圾回收机制的引入,得到了很好的解决。所以, Java 中的内存泄漏,主要指的是第二种情况。而C++则包含以上两种情况。在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度。我们有时也将其称为“对象游离”。

    要避免这种情况下的内存泄露,要求我们以C/C++ 的内存管理思维来管理自己分配的内存。第一,是在声明对象引用之前,明确内存对象的有效作用域。在一个函数内有效的内存对象,应该声明为局部变量,与类实例生命周期相同的要声明为实例变量……以此类推。第二,在内存对象不再需要时,记得手动将其引用置空。

    三、引用和指针

    1. 引用与指针有什么区别?

    1) 引用必须被初始化,指针不必。

    2) 引用初始化以后不能被改变,指针可以改变所指的对象。

    3) 不存在指向空值的引用,但是存在指向空值的指针。

    4)sizeof引用对象得到的是所指对象,变量的大小;sizeof指针得到的是指针本身的大小

    5)内存分配上,程序为指针变量分配内存,不为引用分配内存。

    6)指针可有多级,引用只可一级

    7)作为函数参数都能实现引用传递

    2. 什么是引用?申明和使用“引用”要注意哪些问题?

    引用就是某个目标变量的“别名”,声明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因为该引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用,意思是数组的元素不能是引用,如:int& b[3]; 原因是没法完成数组元素的复制操作(引用不支持传统意义的复制,传统意义的复制:int a = b;a和b在内存中分别占用,内容一致)。但是可以声明数组名的引用,如:int arr[3]; int (&tef)[3] = arr;

    3. 将“引用”作为函数参数有哪些特点?

    1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对相应的目标对象(在主调函数)的操作。

    2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

    3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

    4. 在什么时候需要使用“常引用”?

    如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;如const int &ra=a;此时可以直接改变a的值,但不能通过别名ra改变a的值。

    5. 将“引用”作为函数返回值类型的好处和需要遵守的规则?

    好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

    注意事项:

    1)不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。

    2)不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况,又面临其它尴尬局面。例如,被函数返回的引用只是作为一个别名出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak

    3)可以返回类成员的引用,但最好是const

    4)流操作符、赋值操作符重载返回值申明为“引用”的作用:使其可以连续使用。如:cout << "hello" << endl; x = j = 10;+-*/ 四则运算符不能返回引用,必须构造一个对象作为返回值。

    6. 引用与多态的关系?

    引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的派生类实例

    四、全局变量、静态变量、局部变量,static和const, volatile关键字,new和malloc

    1. 全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?   

    全局变量和局部变量的区别是作用域和生命周期不同,全局变量从定义位置开始到程序结束,而局部变量只限定义的函数内可使用,内存分配位置不同,全局变量在静态存储区,而局部变量在栈,局部变量在函数结束时内存空间就被系统收回。extern和在main()函数外定义的变量都称为全局变量,操作系统和编译器从定义变量为变量分配内存时,从变量的定义和存储区域来分辨局部变量和全局变量.

    2. static全局变量与普通的全局变量的区别:

    都有全局生命周期,但是作用域不同。非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域,只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。

    3. 关键字static的作用:

    1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变

    2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问,它是一个本地的全局变量

    3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

    优点:因为静态变量对所有对象所公有的,可以节省内存,提高时间效率。

    缺点:不安全,因为作用域是全局的。

    4. const关键字至少有下列5个作用:  

    1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;  

    2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;  

    a. const char *ptr; //定义一个指向字符常量的指针,这里,ptr是一个指向 char* 类型的常量,所以不能用ptr来修改所指向的内容,换句话说,*ptr的值为const,不能修改。但是ptr的声明并不意味着它指向的值实际上就是一个常量,而只是意味着对ptr而言,这个值是常量。

    const char *ptr="hello";//"hello"是常量

    str="hello";const char *ptr=str;//ptr指向str,而str不是const,可以直接通过str变量来修改str的值,但是确不能通过ptr指针来修改。

    b. char const *ptr;//此种写法和const char *等价

    c. char * const ptr;//定义一个即const指针,不能修改ptr指针,但是可以修改该指针指向的内容。

    3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;  

    4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;  

    5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。

    5. volatile关键字的作用

    volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。

    例如:
    volatile int i=10;
    int j = i;
    ...
    int k = i;

     volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。

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

    6. new、delete、malloc、free之间的关系

    malloc和free都是C/C++语言的标准库函数,new/delete是C++的运算符。new调用构造函数,delete会调用对象的析构函数,而free只会释放内存。它们都可用于申请动态内存和释放内存。但对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加给malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意:new/delete不是库函数。

    五、类和对象相关、虚函数

    1. 构造函数:

    用于对象的初始化,是类的成员函数,可以重载。构造函数不能声明为虚函数。

    一般构造函数声明为公有函数,如果说明为私有或保护,就不能在定义对象时使用,程序中不能显式调用构造函数,在创建对象时由系统自动调用构造函数。

    2. 析构函数:

    析构函数用于完成内存的清理工作,~类名(),不允许有返回值和形参,析构函数不能被继承,需在派生类中重新定义。

    3. 什么时候需要重写析构函数和复制构造函数

    自定义析构函数:当你的类内部有需要手动释放内存的成员变量(动态分配的内存)时,需要自定义析构函数,防止内存泄露。

    自定义复制构造函数:程序自动生成的复制构造函数是浅拷贝,当你的类需要深拷贝(动态申请空间)的时候,需要自定义复制构造函数。这样也可以防止一些意外的事情发生,浅拷贝中临时对象就会和原对象指向同一块内存,而当临时对象在作用域外被释放时,那么原对象的内存空间也就同时被释放了,之后再次引用原对象就会出问题。

    4. 虚函数的用法和作用:

    虚函数是用于实现动态多态的,相同的方法对于不同的类型的对象有着不同的操作。virtual 《返回值类型》 《成员函数名》 (参数表)需要通过基类的指针对象或引用,使该指针指向不同派生类的对象,并通过指针对象调用虚函数,指针对象指向的对象属于哪个类就调用哪个类的虚函数。构造函数不能声明为虚函数,析构函数可以为纯虚函数。

    5. 虚函数和纯虚函数

    使用虚函数是为了实现接口的重用,在基类中规定统一的接口形式,在派生类中重新定义具体实现。某些情况下,基类中虚函数无法定义具体的实现部分,就可以定义纯虚函数,没有函数体,其函数体由派生类定义。含有纯虚函数的基类叫做抽象类,抽象类不能定义对象(在很多情况下,基类本身生成对象是不合情理的),只能派生。但仍可使用指向抽象类的指针支持运行时多态性。

    定义一个函数为虚函数,不代表函数为不被实现的函数。定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。

    定义一个函数为纯虚函数,才代表函数没有被实现。

    6. C++中虚函数是怎么实现的?

    每一个含有虚函数(无论是其本身的,还是继承而来的)的类都至少有一个与之对应的虚函数表,其中存放着该类所有的虚函数对应的函数指针。基类的虚函数表的创建:首先在基类声明中找到所有的虚函数,然后按照声明顺序为基类创建一个虚函数表,其内容就是指向这些虚函数的函数指针,按照虚函数声明的顺序将这些虚函数的地址填入虚函数表中。对于子类的虚函数表:首先将基类的虚函数表复制到该子类的虚函数表中。若子类重写了基类的虚函数show,则将子类的虚函数表中存放show的函数地址(未重写前存放的是基类的show虚函数的函数地址)更新为重写后函数的函数指针。若子类增加了一些虚函数的声明,则将这些虚函数的地址加到该类虚函数表的后面。当执行pBase->show()时,要观察show在Base基类中声明的是虚函数还是非虚函数。若为虚函数将使用动态联编(使用虚函数表决定如何调用函数),若为非虚函数则使用静态联编(根据调用指针pBase的类型来确定调用哪个类的成员函数)。此处假设show为虚函数,首先:由于检查到pBase指针类型所指的类Base中show定义为虚函数,因此找到pBase所指的对象(有可能是Base类型也可能是Extend类型。),访问对象得到该对象所属类的虚函数表地址。其次:查找show在Base类中声明的位置在Base类中所有虚函数声明中的位序。然后到pBase所指对象的所属类(有可能是Extend哦,多态)的虚函数表中访问该位序的函数指针,从而得到要执行的函数。

    如何判断浮点数是否为0,或判读两个浮点数是否相等

    注意计算机无法精确表达浮点数,abs(x-target)<epsilon.( epsilon是一个很小的数)

    new、malloc的差别,单例类,怎样使堆里的内存自己主动释放。多线程中栈是共享么?

    vector是怎样实现的,数组和链表的差别,插入语删除的时间复杂度,vector插入n个元素的时间复杂度。

    展开全文
  • c++知识点复习重点

    2011-12-11 11:17:18
    c++ 自己总结的一些考点 对考试很有帮住
  • 学习c++已经差不多两个多月了 该整理一些自己容易忘记的知识点!!!(以下内容全部靠记忆 有错误 但之后会检查) 写的很乱!!! 这个是重点 哈哈。 1、输出时精确到小数点第几位 : 头文件 :#include cout   #...

    学习c++已经差不多两个多月了 该整理一些自己容易忘记的知识点!!!(以下内容全部靠记忆  有错误 但之后会检查)  写的很乱!!!  这个是重点  哈哈。

    1、输出时精确到小数点第几位  : 头文件 :#include<iomanip>    cout<<setiosflags(ios::fixed)<<setprecision(n)<<a;  注意的是 a的类型应该是 float  或者是 double

      


    #include<iomanip> 
    #include<iostream>
    using namespace std;
    int main()
    {
        float a=1;
        cout<<setiosflags(ios::fixed)<<setprecision(2)<<a;
        return 0; 
    }
      

                  

    2、判断是否为数字的函数:  头文件 : #include<ctype.h>      函数   isalnum(a);
    
    
    #include<iostream>
    #include<ctype.h>
    using namespace std;
    int main()
    {
        char a='1'
        if(isalnum(a))
          cout<<"No";
        return 0; 
    }
    
    
    3、  sort函数 比冒泡省事多了  头文件 :#inlcude<algorithm> 目前我只会用这个排序 数组 
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int main()
    {
        int a[5]={3,1,2,4,5};
       int b;
       sort(a,a+5);
       for(b=0;b<5;b++)
          cout<<a[b];     //这个输出是按照从小到大输出的  还有就是 有时候会看到sort(a,a+n,cmp)这种形式  cmp 是自定义函数 自己写的
      return 0;  
    }
    
    
    4、在遇到题的时候我们最会遇到开头和结尾没有空格  只有每个数之间有空格的情况   我感觉 这个方法很好 
    #include<iostream>
    using namespace std;
    int main()
    {
          int a[3];
          int b,c;
         for(b=0;b<3;b++)
           {   
                 if(c==1)
                     cout<<" ";
                 cout<<a[b];
                 c=1;
            }
      return 0;
    }
    这样的话输出时只有中间有空格  结尾和开头没有
    
    
    
    

    展开全文
  • const成员函数(非静态):(重点) 1.const关键字写在参数列表后面, 函数的声明和实现都必须带const 2.内部不能修改非static成员变量. static成员变量的内存全世界只有一份, 哪里都可以修改, 而这个const的作用是限制了...

    const成员, 引用成员

    const成员: 被const修饰的成员变量, 非静态成员函数.
    const成员变量:
    1.必须初始化(必须在类内部初始化), 可以在声明的时候直接初始化赋值.
    2.非static的const成员变量还可以在初始化列表中初始化.
    const成员函数(非静态):(重点)
    1.const关键字写在参数列表后面, 函数的声明和实现都必须带const
    2.内部不能修改非static成员变量.
    static成员变量的内存全世界只有一份, 哪里都可以修改, 而这个const的作用是限制了这个成员函数里面不能修改非static的成员变量.
    3.内部只能调用const成员函数, static成员函数.
    4.非const成员函数可以调用const成员函数
    5.const成员函数和非const成员函数可以构成重载.
    非const对象(指针)优先调用非const成员函数
    const对象(指针)只能调用const成员函数, static成员函数.

    #include <iostream>
    using namespace std;
    
    class Car {
    public:
        const int mc_price;
        Car() : mc_price(0) {}
        void run() const {
            cout << "run()const" << endl;
        }
        void run() {
            cout << "run()" << endl;
        }
    };
    
    int main()
    {
        Car car;
        car.run();
        const Car car1;
        car1.run();
        return 0;
    }
    

    引用类型成员

    1.引用类型成员变量必须初始化(不考虑static情况, 很少)
    2.在声明的时候直接初始化, 或者通过初始化列表初始化.

    #include <iostream>
    using namespace std;
    
    class Car {
        int m_age;
        int &m_price = m_age;
    public:
        Car(int &price) : m_price(price) {}
    };
    
    int main()
    {
        return 0;
    }
    

    拷贝构造函数1(Copy Constructor) (重点)

    1.拷贝构造函数是构造函数的一种
    2.当利用已存在的对象创建一个新对象时(类似于拷贝), 就会调用新对象的拷贝构造函数进行初始化.
    3.拷贝构造函数的格式是固定的, 接收一个const引用作为参数

    #include <iostream>
    using namespace std;
    
    class Car {
        int m_price;
        int m_length;
    public:
        Car(int price = 0, int length = 0) : m_price(price), m_length(length) {
            cout << "Car(int price = 0, int length = 0)" << endl;
        }
        // 拷贝构造函数
        Car(const Car &car) {
            cout << "Car(const Car &car)" << endl;
            m_price = car.m_price;
            m_lengh = car.m_lengh;
        }
    
        void display() {
            cout << "price =" << m_price << ", length = " << m_length << endl;
        }
    };
    
    int main()
    {
        Car car1;
        Car car2(100);
        Car car3(100, 5);
        // 利用已经存在的car3对象创建了一个car4新对象
        // car4初始化时会调用拷贝构造函数
        Car car4(car3);
        car4.display();
        return 0;
    }
    

    默认时, 如果没有写拷贝构造函数的话, 就不会帮你生成一个拷贝构造函数, 那他是怎么拷贝的呢?
    默认的拷贝操作是: 类似于car4.m_price = car3.m_price; car4.m_length = car3.m_length;
    从car3对象的地址开始的8个字节覆盖掉car4的8个字节
    默认的拷贝会这个旧对象的所有数据(字节)全部覆盖掉另外一个对象的所有字节.
    有写拷贝构造函数时: 会调用拷贝构造函数去初始化对象.此时系统默认的拷贝操作就不存在了.

    拷贝构造2-调用父类的拷贝构造函数

    #include <iostream>
    using namespace std;
    
    class Person {
    public:
        int m_age;
        Person(int age = 0) : m_age(age) {}
        Person(const Person &person) : m_age(person.m_age) {}
    };
    
    class Student : public Person {
    public:
        int m_score;
        Student(int age = 0, int score = 0) : Person(age), m_score(score) {}
        // 因为Student继承Person所以创建Student对象时, 又有age又有score
        Student(const Student &student) : Person(student), m_score(student.m_score) {}
        // 调用父类的拷贝构造函数
    };
    
    int main()
    {
        Student stu1(18, 100);
        Student stu2(stu1);
        cout << stu2.m_age << endl;
        cout << stu2.m_score << endl;
        return 0;
    }
    

    拷贝构造3-注意点

    	Car car1(100, 5);
    	Car car2(car1); // 拷贝构造
    	Car car3 = car2;  // 拷贝构造与上一个等价(两种写法是等价的)创建car3的同时传了个car2, 通过car2来创建car3, 通过已经存在的对象创建新对象
    	Car car4; 
    	car4 = car3; // car4是已经存在的对象(不是在创建新对象), 不会调用拷贝构造.仅仅是简单的赋值操作, 构造函数是在对象创建完之后马上调用的.
    

    拷贝构造4-浅拷贝, 深拷贝

    编译器默认的提供的拷贝是浅拷贝(shallow copy)
    1.将一个对象中所有的成员变量的值拷贝到另一个对象
    2.如果某个成员变量是个指针, 只会拷贝指针中存储的地址值, 并不会拷贝指针指向的内存空间
    3.可能会导致堆空间多次free的问题(如果堆空间指向栈空间, 栈空间无法控制它的生命周期, 如果栈空间释放了, 堆空间的指针就指向了已经销毁的空间, 就成了野指针.)所以所有的堆空间指向栈空间都是危险的.
    如果需要实现深拷贝(deep Copy), 就需要自定义拷贝构造函数
    将指针类型的成员变量所指向的内存空间, 拷贝到新的内存空间

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    class Car {
    private:
        int m_price;
        char *m_name;
        void copyName(const char *name) {
            if (name == NULL) return;
            // 申请新的堆空间
            m_name = new char [strlen(name) + 1] {};
            // 拷贝字符串数据到新的堆空间
            strcpy(m_name, name);
        }
    public:
        Car(int price = 0, const char *name = NULL) : m_price(price) {
            copyName(name);
        }
        Car(const Car &car) : m_price(car.m_price) {
            copyName(car.m_name);
        }
        ~Car() {
            if (m_name != NULL) {
                delete[] m_name;
                m_name = NULL;
            }
        }
        void display() {
            cout << "price is" << m_price << ", name is" << m_name << endl;
        }
    };
    
    int main()
    {
        Car car1(100, "bmw");
        Car car2 = car1;
        car2.display();
        return 0;
    }
    

    总结:拷贝构造函数这个东西只有在你需要进行深拷贝的时候, 才需要写.(类里面全是普通数据类型, 没有指针不需要写拷贝构造函数, 而有指针时, 对象在堆空间时, 堆空间的指针指向栈空间就很危险, 就需要写拷贝构造函数完成深拷贝, 而且如果不写, 直接浅拷贝的话, 会直接将指针里面存储的地址值拷贝过去, 导致两个对象的指针指向同一个东西.)


    其他C++系列文章:

    C++知识点总结(基础语法1-函数重载, 默认参数)
    C++知识点总结(基础语法2-内联函数, const, 引用)
    C++知识点总结(面向对象1-类和对象, this指针, 内存布局)
    C++知识点总结(面向对象2-构造函数, 初始化列表)

    C++知识点总结(面向对象3-多态)

    C++知识点总结(面向对象4-多继承, 静态成员static)
    C++知识点总结(面向对象5-const成员, 拷贝构造函数)
    C++知识点总结(面向对象6-隐式构造, 友元, 内部类, 局部类)
    C++知识点总结(其他语法1-运算符重载)
    C++知识点总结(其他语法2-模板, 类型转换, C++11新特性)

    展开全文
  • 是根据老师的PPT与自己所学进行总结的,基本不涉及偏难怪知识点重点是为了期末考试。 全文长6400多字,基本可以囊括90%的考试知识点 个人感觉知识掌握了就是多做做往年习题,毕竟考试偏应试,想提高分请一定多做题...
  • 很多小伙伴想要好好地学习一下C语言的知识,但是又不知道怎么学,应该学哪一些C语言的知识,笔者在网上看到了这一张C语言的比较完善的C语言的学习路线图,有兴趣的小伙伴可以保存起来哈! C语言是面向过程的,而...
  • Linux多线程服务端编程知识点总结 重点讲解多线程网络服务器的一种IO模型,即one loop per thread。以muduo网络库为例,讲解这种模型的编程方法及注意事项。 muduo是一个基于非阻塞IO和事件驱动的现代C++网络库。 第...
  •  STL是C++重要的组件之一,大学时看过《STL源码剖析》这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1、STL概述 STL提供六大组件,彼此可以组合套用: 容器(Containers
  • 自开学以来都没有写程序设计的blog总结,今天就大概总结一下,因为知识有点多,就不总结那么详细了,就简单的写一点我认为的重点难点吧。 我们这本书是从第四章开始学的,因为之前也学习过stl,我觉得第四章的知识...
  • c++总结

    2019-01-04 18:14:03
    从最开始学习的常量变量,到最后学到的分支语句,再到后来学到循环以及数组函数,以及各个琐碎的知识点,现在的我可以独立码一些简单代码,相信以后还会有更大的进步,下面介绍一下本学期学到的一些较为重点的知识。...
  • STL是C++重要的组件之一,大学时看过《STL源码剖析》这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1、STL概述 STL提供六大组件,彼此可以组合套用: 1.容器(Containers):各种...
  • 24位彩图转换为灰度图练习练习目的位图知识点BMP图像存储结构位图文件头位图信息头调色板位图数据转灰度图重点代码例程 练习目的 对jpg格式的图片滤波去噪点,并进行边缘提取 位图知识点 刚拿到任务时觉得图像...
  • STL是C++重要的组件之一,大学时看过《STL源码剖析》这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1、STL概述 STL提供六大组件,彼此可以组合套用: 容器(Containers):...
  • C++并发编程实战总结1

    2020-05-08 15:25:29
    刚读了几章,看了一下目录,发现知识点还是挺多的,对于初学者的我来说暂时应该是够了。唯二让我觉得很是不满的地方就是这个翻译和排版,感觉出版社不是很用心,有的时候翻译的就跟不是中文一样,绕来绕去的没看明白...
  • C++学习总结系列

    2016-07-13 14:07:24
    由于个人爱好,笔者将开始总结在学习c++过程中遇到的重点知识,也包含平时编程中容易忽略的知识点,学习过程将会依据c++11的标准,笔者也希望自己能够坚持下去,追求技术,享受生活。
  • 有一个关于类成员初始化列表的小知识点,即采用成员初始化列表的方法初始化数据成员的时候之直接使用对应的复制构造函数进行初始化,而常规初始化则往往需要先对成员使用默认构造函数,再通过赋值运算符将参数赋值给...
  • STL是C++重要的组件之一,大学时看过《STL源码剖析》这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1、STL概述 STL提供六大组件,彼此可以组合套用: 容器(Containers):...
  • 总结c++学习

    千次阅读 2013-02-23 21:44:05
    老师每周都会布置作业让我们编程序,一些重点知识会在课上提出来讲解,但是感觉听得好迷茫,自己在编程时还是不理解,不会运用,总之理解的不够透彻。越是不明白,上课越是没精神,越是听不进去,久而久之,就感觉...
  • 最近在学习C++时,进入到了STL的学习阶段,在发现到这个部分的重要性时,我打算把对STL的学习分步骤记录下来,我首先打算学习的是组件String的部分,此文章主要只...先放一张我学习String后对于此部分知识点的概括。...
  • 上次裸考蓝桥杯c++,只拿了个省三,遗憾无限~ 这一次无论如何都要弥补一下,emmm,算是对我大学时光的纪念吧。。。 话不多说:蓝桥杯java重点 枚举以及优化 递归(回溯,剪枝):八皇后,全排列 dfs ,bfs,二...

空空如也

空空如也

1 2 3 4 5 6
收藏数 101
精华内容 40
关键字:

c++重点知识点总结

c++ 订阅