C++

https://www.zhihu.com/question/34574154?sort=created
1、面向对象特点
封装,继承和多态。

2、子类析构时要调用父类的析构函数吗?
定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数
析构的时候恰好相反:先调用派生类的析构函数、然后调用基类的析构函数

4、C++ STL
STL(Standard Template Library),即标准模板库
STL作为一个泛型化的数据结构和算法库
在C++标准中,STL被组织为以下的13个头文件:

5、STL中的Set与Map
他们的底层都是以红黑树的结构实现

   //map声明,加入有文件map 
    map m;

    //插入元素要用makr_pair的方式 
    m.insert(make_pair(1, 5));

    //通过iterator来查找map里面的元素 
    map::iterator ite;
    ite = m.find(1);
    set s;
    //向集合中插入元素 
    s.insert(1);
    //在集合中查找元素 
    set::iterator ite;
    ite = s.find(1);

3、多态
C++的多态体现在两方面:
在程序运行时的多态性通过继承和虚函数来体现;
在程序编译时多态性体现在函数和运算符的重载上;

多态的目的:为了接口重用。不论传递过来的是哪个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。
最常见的用法就是声明基类的指针利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。

从基类继承来的虚函数,在派生类中仍是虚函数。
如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类

4、指针和引用的区别
相同点:
●都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

不同点:
●指针是一个实体,而引用仅是个别名;
●引用只能在定义时被初始化一次,之后不可变;指针可变;
●引用不能为空,指针可以为空;
●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;

5、Struct与class的区别
struct能包含成员函数吗? 能!
struct能继承吗? 能!!
struct能实现多态吗? 能!!!
最本质的一个区别就是默认的访问控制:
默认的继承访问权限 struct是public的,class是private的。

Protected
在没有继承的情况下,protected跟private相同.
基类对象不能访问基类的protected成员,派生类中可以访问基类的protected成员。也就是说private成员是不能被继承的,只有public,protected的成员才可以被继承。
只有在派生类中才可以通过派生类对象访问基类的protected成员。

6、malloc和new的区别
1malloc/free是库函数,需要头文件支持。
2new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。
3new操作符内存分配成功时,返回的是对象类型的指针,无须进行类型转换,而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
4new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。

8、define与const的区别
const 定义的常数是变量带类型,#define 定义的只是个常数,不带类型。
define是在编译的预处理阶段起作用,而const是在 编译、运行的时候起作用。
define只是简单的字符串替换,没有类型检查。而const有对应的数据类型,是要进行判断的

一.虚函数&纯虚函数

a、虚函数表
虚函数是通过一张虚函数表来实现的。

b、a representative instance
区别覆盖和隐藏

class Base
{
public:
    virtual void f(float x)
    {
        cout<<"Base::f(float)"<< x <

函数Derived::g(int)隐藏了Base::g(float),而不是重载。

c、重载,隐藏(重定义),覆盖(重写)
重载:函数名相同,参数列表不同,返回值类型可相同也可不同

覆盖(重写)的前提条件:父类函数为虚函数
在子类中定义了一个与父类完全相同的虚函数

隐藏:如果在父类和子类中有相同名字的成员;那么在子类中会将父类的成员隐藏

d、纯虚函数
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法
在基类中实现纯虚函数的方法是在函数原型后加“=0”

  virtual void funtion()=0 

二.static关键字

采用static可以实现不同对象之间数据共享。

a、static修饰局部变量
static修饰局部变量时,使得被修饰的变量成为静态变量存储在静态区
存储在静态区的数据生命周期与程序相同,在main函数之前初始化,在程序退出时销毁

局部静态变量使得该变量在退出函数后,不会被销毁,因此再次调用该函数时,该变量的值与上次退出函数时值相同。

void function()
{
    static int nCount(0);    
}

b、static修饰全局变量
全局变量本来就存储在静态区,因此static并不能改变其存储位置。
被static修饰的全局变量只能被该包含该定义的文件访问

c、static修饰函数
static修饰函数使得函数只能在包含该函数定义的文件中被调用
对于静态函数,声明和定义需要放在同一个文件夹中

在多人协同工作的项目中,为了避免出现同名的函数冲突,可以将函数定义为static,从而避免冲突的发生。

三.extern

修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”
extern声明不是定义,即不分配存储空间

用extern "C" 来强制编译器不要修改你的函数名:

extern "C" {  
int ThisIsTest(int, int);            
} 

四、析构函数

C++标准指明析构函数不能抛出异常
析构函数不能重载。每有一次构造函数的调用就会有一次析构函数的调用
一个类只能有一个析构函数,如果没有显式的定义,系统会生成一个缺省的析构函数。
它不会帮助我们去打开文件、连接数据库、分配内存这些操作,相应的回收,它也不会给我们写。所以需要我们自己手动的写。

Keynote:对象的构造和析构的关系是栈数据结构中的入栈和出栈的关系。

Keynote2:重载拷贝构造就一定要对赋值运算符做对应处理。

 Person& operator=(const Person& pr) {
       ……
    }
Person  B = A; //注意这里的对象初始化要调用拷贝构造函数,而非赋值 

五、指针与数组
a、usage

int a = 4;
int* p = &a;

将p的值设置为&a。

.在C++中创建指针时,计算机将分配用来存储指针的内存,但不会分配用来存储指针所指向的数据的内存。
所以如下是不允许的

int* b;
*b = 22;

b、与数组
C++将数组名解释为地址
区别:①可以修改指针的值,但是数组名是常量,其不能作为左值

六、HashTable
a、introduction
哈希表,是根据关键码值(Key value)而直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。

记录的存储位置=f(关键字)
哈希表就是把Key通过一个固定的算法函数(哈希函数转)换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标将value存储在以该数字为下标的数组空间里
而当使用哈希表进行查询的时候,就是再次使用哈希函数将key转换为对应的数组下标,并定位到该空间获取value。

数组的特点是:寻址容易,插入和删除困难;
而链表的特点是:寻址困难,插入和删除容易。

b、hashmap如何解决哈希冲突
链表法和开放地址法。链表法就是将相同hash值的对象组织成一个链表放在hash值对应的槽位;
开放地址法是通过一个探测算法,当某个槽位已经被占据的情况下继续查找下一个可以使用的槽位。按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。

七、
快速排序:哨兵交叉后将左边的指针与基准进行交换

抽象类和抽象方法

八、解决循环引用
解除这种循环引用有下面有三种可行的方法([参考]
1. 当只剩下最后一个引用的时候需要手动打破循环引用释放对象。
2. 当A的生存期超过B的生存期的时候,B改为使用一个普通指针指向A。
3. 使用弱引用的智能指针打破这种循环引用。
一般都只用方法3

强引用
当对象被创建时,计数为1;每创建一个变量引用该对象时,该对象的计数就增加1;当上述变量销毁时,对象的计数减1,当计数为0时,这个对象也就被析构了。

由于弱引用不更改引用计数,类似普通指针,只要把循环引用的一方使用弱引用,即可解除循环引用。

九、C++的内存管理机制
内存分成五个区:
a、栈:函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
b、堆:就是那些由 new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个 delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
c、自由存储区:就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
d、全局/静态存储区:全局变量和静态变量被分配到同一块内存中
e、常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。

你可能感兴趣的:(C++)