C++常问考点

一、封装,继承,多态,虚函数

封装:封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类)。封装的意义在于保护或者防止代码(数据)被我们无意中破坏。

继承:继承主要实现重用代码,节省开发时间。子类可以继承父类的一些东西。

多态:是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态。

A. 多态

定义: “一个接口,多种方法”,程序在运行时才决定调用的函数。
实现: C++多态性主要是通过虚函数实现的,虚函数允许子类重写override(注意和overload的区别,overload是重载,是允许同名函数的表现,这些函数参数列表/类型不同)。
目的: 封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。

B.什么是虚函数,什么函数不能声明为虚函数?

  • 那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。

  • 构造函数。因为要构造一个对象,必须清楚地知道要构造什么,否则无法构造一个对象。析构函数可以为纯虚函数。

C.为什么要用纯虚函数?

在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。为了解决这个问题,方便使用类的多态性,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。

D. 在什么情况下使用纯虚函数(pure vitrual function)?

  1. 当想在基类中抽象出一个方法,且该基类只做能被继承,而不能被实例化;
  2. 这个方法必须在派生类(derived class)中被实现;

E. 虚函数与纯虚函数的区别

虚函数为了重载和多态。 在基类中是有定义的,即便定义为空。 在子类中可以重写。
纯虚函数在基类中没有定义, 必须在子类中加以实现。

多态的基础是继承,需要虚函数的支持,简单的多态是很简单的。
子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数, operator=函数,友元函数等等

二、开发中常用到的数据结构

 

数组,链表,树。也会用到栈(先进后出)和队列(先进先出)。

1.数组和链表的区别。(很简单,但是很常考,记得要回答全面)

C++语言中可以用数组处理一组数据类型相同的数据,但不允许动态定义数组的大小,即在使用数组之前必须确定数组的大小。而在实际应用中,用户使用数组之 前有时无法准确确定数组的大小,只能将数组定义成足够大小,这样数组中有些空间可能不被使用,从而造成内存空间的浪费。链表是一种常见的数据组织形式,它 采用动态分配内存的形式实现。需要时可以用new分配内存空间,不需要时用delete将已分配的空间释放,不会造成内存空间的浪费。
  
从逻辑结构来看:
数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况,即数组的大小一旦定义就不能改变。当数据增加时,可能超出原先 定义的元素个数;当数据减少时,造成内存浪费;链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删 除数据项时,需要移动其它数据项)。  
从内存存储来看:
(静态)数组从栈中分配空间(用NEW创建的在堆中), 对于程序员方便快速,但是自由度小;链表从堆中分配空间, 自由度大但是申请管理比较麻烦.
从访问方式来看:
数组在内存中是连续存储的,因此,可以利用下标索引进行随机访问;链表是链式存储结构,在访问元素的时候只能通过线性的方式由前到后顺序访问,所以访问效率比数组要低。

2. 二叉树的遍历

二叉树的遍历,就是按照某条搜索路径访问树中的每一个结点,使得每个结点均被访问一次,而且仅被访问一次。

  • 常见的遍历次序有:
    先序遍历:先访问根结点,再访问左子树,最后访问右子树
    中序遍历:先访问左子树,再访问根结点,最后访问右子树
    后序遍历:先访问左子树,再访问右子树,最后访问根结点
  • 时间复杂度 O(n)
    http://www.linuxidc.com/Linux/2015-08/122480.htm

三. const与static的用法

1. const:

  • const修饰类的成员变量,表示该成员变量不能被修改。
  • const修饰函数,表示本函数不会修改类内的数据成员。不会调用其他非const成员函数。
  • const函数只能调用const函数,非const函数可以调用const函数
    类外定义的const成员函数,在定义和声明出都需要const修饰符。

2. static:

2.1 对变量:

a. 局部变量:
在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。位于内存中静态存储区; 未初始化的局部动初始化为0. 作用域仍是局部作用域.注:当static用来修饰局部变量的时候,它就改变了局部变量的存储位置(从原来的栈中存放改为静态存储区)及其生命周期(局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对他进行访问),但未改变其作用域。

b. 全局变量.
在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。静态存储区,未经初始化的全局静态变量会被程序自动初始化为0,全局静态变量在声明他的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。注: static修饰全局变量并未改变其存储位置及生命周期, 而是改变了其作用域,使得当前文件外的源文件无法访问该变量.不能被其他文件访问和修改,其他文件中可以使用相同名字的变量,不会产生冲突.

2.2 对类:

a. 成员变量. 

用static修饰类的数据成员实际使其成为类的全局变量,会被类的所有对象共享,包括派生类的对象。因此,static成员必须在类外进行初始化(初始化格式: int base::var=10;),而不能在构造函数内进行初始化,不过也可以用const修饰static数据成员在类内初始化 。
注意:

  • 不要试图在头文件中定义(初始化)静态数据成员。在大多数的情况下,这样做会引起重复定义这样的错误。即使加上#ifndef #define #endif或者#pragma once也不行。
  • 静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以。
  • 静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为 所属类类型的指针或引用。

b. 成员函数

注意:

a. 用static修饰成员函数,使这个类只存在这一份函数,所有对象共享该函数,不含this指针。

b. 静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。base::func(5,3);当static成员函数在类外定义时不-需要加static修饰符。

c. 在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员。因为静态成员函数不含this指针。

d. 不可以同时用const和static修饰成员函数。

C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候,该函数是没有this指针的。也就是说此时const的用法和static是冲突的。

我们也可以这样理解:两者的语意是矛盾的。static的作用是表示该函数只作用在类型的静态变量上,与类的实例没有关系;而const的作用是确保函数不能修改类的实例的状态,与类型的静态变量没有关系。因此不能同时用它们。

四、 类的static变量在什么时候初始化,函数的static变量在什么时候初始化。

类的静态成员在类实例化之前就存在了,并分配了内存。函数的static变量在执行此函数时进行实例化。

五、 指针和引用

  • 指针是一个变量,存放地址的变量,指向内存的一个存储单元,引用仅是个别名。
  • 引用必须被初始化, 指针不必
  • 引用使用时无需加*。
  • 引用没有const修饰,指针有const修饰
  • sizeof引用对象得到的是所指对象,变量的大小;sizeof指针得到的是指针本身的大小
  • 指针可有多级,引用只可一级
  • 内存分配上,程序为指针变量分配内存,不为引用分配内存。

1. 引用作为参数的优点:

(1)传递引用给函数与传递指针的效果是一样的。
(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!;
(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

2. 引用与多态的关系?

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

六、 内存

1.内存类别

 --由编译器自动分配释放, 局部遍历存放位置
 --由程序员分配和释放.
全局区(静态区) --全局变量和静态变量的存储是放在一起的, 初始化的全局变量和static静态变量在一块区域.
程序代码区 --存放二进制代码.

在函数体中定义的变量通常是在栈上, 用malloc, 等分配内存的函数分配得到的就是在堆上. 在所有函数体外定义的是全局量, 加了static修饰符后不管在哪里都存放在全局区, 在所有函数体外定义的static变量表示在该文件有效, 不能extern 到别的文件用. 在函数体内定义的static表示只在该函数体内有效.

2. 堆栈溢出的原因:

数组越界, 没有回收内存, 深层次递归调用

3. 内存分配方式

内存分配的三种方式: a 静态存储区,程序编译时便分好, 整个运行期间都存在,比如全局变量,常量; b, 栈上分配; 堆上分配。

4. 避免内存泄漏

原因:动态分配的内存没有手动释放完全.
避免:使用的时候应记得指针的长度; 分配多少内存应记得释放多少, 保证一一对应的关系; 动态分配内存的指针最好不要再次赋值.

七、c++函数值传递的方式

值传递, 指针传递, 引用传递

八、h头文件中的ifndef/define/endif 的作用?

防止该头文件被重复引用。

 持续更新中。。。。。。

转载:https://www.cnblogs.com/bozhicheng/p/6259784.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值