1、什么是static关键字?
我心想,这还不简单吗?声明静态变量、函数的关键字啊。然后我就这么说了,然后就没然后了。
事后,我看了一下标准回答,大致是这样的,我复述一遍,不然就被举报抄袭了。
1、在变量前加上该关键字,变量就变成了静态变量。
2、未经初始化的静态变量默认为0。
3、静态变量存储在静态存储区,在整个程序运行的过程中一直存在。
4、如果是全局静态变量,则只在声明它的文件中可见,准确的说,是从声明开始,到文件结束。
5、如果是局部静态变量,作用域仍是局部作用域。
但是当作用域结束,局部静态变量依旧保存在静态存储区中,只是我们无法访问,直到函数再次被调用,其值不变。
6、静态函数。静态函数的定义和声明默认都是extern的。
7、函数的实现使用static修饰,那么这个函数只可在本cpp内使用,不会同其他cpp中的同名函数引起冲突。
8、不要再头文件中声明static的全局函数,不要在源文件内声明非static的全局函数。
9、类的静态成员。在类中,静态成员可以实现多个对象之间的数据共享,而且还安全。对多个对象来说,静态数据成员只存储一处,供所有对象共用。
10、静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们**都不是对象成员**。因此,对静态成员的引用不需要用对象名。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
够多吧,我顶多答了三四条。
2、什么是野指针?
好,我巴拉巴拉的讲了一大堆,顺带还扯上了智能指针,虽然我也没用过智能指针。
野指针就是指向一个已删除的对象或者未申请访问受限内存区域的指针
- 1
以上是我碰到过的,以下是我还没碰到的(我总不能每一题都在无准备情况下作答吧!!!)
3、说一说c++中四种cast转换
说实话,cast转换我只用过几次,我只知道它跟const脱不了干系。
1、const_cast
用于将const变量转为非const
2、static_cast
用于各种隐式转换,比如非const转const,void*转指针等
3、dynamic_cast(不是很懂)
用于动态类型转换。只能用于含有虚函数的类。
向上转换:指的是子类向基类的转换
向下转换:指的是基类向子类的转换
4、reinterpret_cast(这个更没听说过了)
几乎什么都可以转,比如将int转指针,可能会出问题,尽量少用;
5、为什么不使用C的强制转换?
C的强制转换表面上看起来功能强大什么都能转,但是转化不够明确,不能进行错误检查,容易出错。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
看这里:
我珍藏很久的了。
4、 请说一下C/C++ 中指针和引用的区别?
1、指针有自己的一块儿空间,而引用只是个别名。使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小;
2、指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象的引用;
3、指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能被改变;
- 1
- 2
- 3
5、智能指针
当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
6、请你来说一下C++中的智能指针
虽然天天跟人家扯皮说智能指针,但是让我真刀真枪的干,我只能说,还没干过。
C++里面有四种智能指针:auto_ptr(已弃用),shared_ptr, weak_ptr, unique_ptr
- unique_ptr:顾名思义,这个指针是独一无二的,属于独占式指针,同一时间内指向同一资源的最多只有一个指针而已。它对于避免资源泄露非常有用。
unique_ptr<string> p1(new string ("unique"));
unique_ptr<string> p2;
p2 = p1;//此时会报错!!
- 1
- 2
- 3
- 4
- 5
编译器认为这种写法是非法的,避免了p1指向无效资源的问题。
- shared_ptr
和unique相对的,shared实现的是共享式拥有。同一时间可以有多个智能指针指向同一资源。该资源会在最后一个指向其的指针销毁时被释放。通过计数机制来纪录当前有多少指针指向同一资源,可以通过成员函数use_count()来查看资源的所有者个数。
当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。
- weak_ptr
weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作,它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造,它的构造和析构不会引起引用记数的增加或减少。weak_ptr是用来解决shared_ptr相互引用时的死锁问题。
其可以检测到所管理的对象是否已经被释放,从而避免非法访问。
注意的是我们不能通过weak_ptr直接访问对象的方法,比如A对象中有一个方法print()
,我们不能这样访问,pa->pb_->print();
英文pb
_是一个weak_ptr
,应该先把它转化为shared_ptr
,如:shared_ptr p = pa->pb_.lock(); p->print();
7、为什么基类的析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?
如果基类的析构函数不是虚函数,那么当使用基类指针指向子类对象的时候,会造成子类对象无法释放,造成内存泄漏。
默认析构函数是虚函数啊,因为虚函数会使用到虚表,是要占用内存的。能省就省吧。
8、请你来说一下函数指针
这题我自我感觉答得还不错了。毕竟之前给人家上课的时候因为这个点尴尬了一会儿。
函数指针本身首先是一个指针,该指针指向一个具体的函数。
在调用函数指针时,是不能再函数指针名后带上括号的,所以函数指针所需参数也需要作为参数传入调用函数中。
9、请你来说一下静态函数和虚函数的区别
我是真不知道这俩还有啥共同点?
静态函数在编译的时候就已经确定运行时机,虚函数在运行的时候动态绑定。虚函数因为用了虚函数表机制,调用的时候会增加一次内存开销。
10、请你说一说你理解的虚函数和多态
多态的实现主要分为静态多态和动态多态,静态多态主要是重载,在编译的时候就已经确定;动态多态是用虚函数机制实现的,在运行期间动态绑定。
11、请你来回答一下const修饰成员函数的目的是什么?
表明函数调用不会对对象做出任何更改,事实上,如果确认不会对对象做更改,就应该为函数加上const限定,这样无论const对象还是普通对象都可以调用该函数。
12、以下四行代码的区别是什么? const char * arr = “123”; char * brr = “123”; const char crr[] = “123”; char drr[] = “123”;
这题是真的比较绕一些了。
const char * arr = “123”;
//字符串123保存在常量区,const本来是修饰arr指向的值不能通过arr去修改,但是字符串“123”在常量区,本来就不能改变,所以加不加const效果都一样
char * brr = “123”;
//字符串123保存在常量区,这个arr指针指向的是同一个位置,同样不能通过brr去修改"123"的值
const char crr[] = “123”;
//这里123本来是在栈上的,但是编译器可能会做某些优化,将其放到常量区
char drr[] = “123”;
//字符串123保存在栈区,可以通过drr去修改
13、说一说C++函数栈空间的最大值
默认是1M,不过可以调整。
14、请你来说一说extern“C”
C++调用C函数需要extern C,因为C语言没有函数重载。
15、请你回答一下new/delete与malloc/free的区别是什么 ?
1、new/delete是C++的关键字,而malloc/free是C语言的库函数。
2、后者使用必须指明申请内存空间的大小,对于类类型的对象,后者不会调用构造函数和析构函数
16、请你说说虚函数表具体是怎样实现运行时多态的?
说真的,这个还真没了解过。
子类若重写父类虚函数,虚函数表中,该函数的地址会被替换,对于存在虚函数的类的对象,在VS中,对象的对象模型的头部存放指向虚函数表的指针,通过该机制实现多态。
17、请你说说C语言是怎么进行函数调用的?
每一个函数调用都会分配函数栈,在栈内进行函数执行过程。调用前,先把返回地址压栈,然后把当前函数的esp指针压栈。
参数压栈顺序:从右到左。
18、请你说说C++如何处理返回值?
生成一个临时变量,把它的引用作为函数参数传入函数内。
19、纯虚函数和虚函数的区别
1、定义方式的不同。
纯虚函数:virtual void func() = 0;
虚函数:virtual void func();
- 1
- 2
2、含有纯虚函数的类称为抽象类,如果一个类中含有纯虚函数,那么任何试图对该类进行实例化的语句都将导致错误的产生,因为抽象基类(ABC)是不能被直接调用的。必须被子类继承重载以后,根据要求调用其子类的方法。
3、虚函数可以被直接使用,也可以被子类(sub class)重载以后以多态的形式调用,而纯虚函数必须在子类(sub class)中实现该函数才可以使用,因为纯虚函数在基类(base class)只有声明而没有定义。
4、在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时候要求前期bind,然而虚函数却是动态绑定(run-time bind),而且被两者修饰的函数生命周期(life recycle)也不一样。
接下来继续把基础相关的过一下,操作系统之类的后面有安排,循序渐进嘛。
20、请你来说一下map和set有什么区别,分别又是怎么实现的?
(1)map中的元素是key-value(关键字—值)对;Set与之相对就是关键字的简单集合,set中每个元素只包含一个关键字。
(2)set的迭代器是const的,不允许修改元素的值;map允许修改value,但不允许修改key。
map和set是根据关键字排序来保证其有序性的,如果允许修改key的话,那么首先需要删除该键,然后调节平衡,再插入修改后的键值,调节平衡,如此一来,严重破坏了map和set的结构,导致iterator失效。
(3)map支持下标操作,set不支持下标操作。
set 底层是通过红黑树(RB-tree)来实现的。又由于 set 所开放的各种操作接口,RB-tree 也都提供了,所以几乎所有的 set 操作行为,都只有转调用 RB-tree 的操作行为而已。
map也是如此。
21、请你来说一说STL迭代器删除元素
这个问题啊,其实已经说过很多遍了,在C++里面说过,在Python里面也说过。
1.对于序列容器vector,deque来说,使用erase(itertor)后,会出现各种各样的问题,比方说出现野指针、foreach中删除啊等的,反正这样写就好:
vector<int>::iterator itor2;
for(vector<int>::iterator iter=veci.begin(); iter!=veci.end(); )
{ if( *iter == 3) { itor2=iter; veci.erase(itor2); } else iter ++ ;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2.对于关联容器map set来说,使用了erase(iterator)后,当前元素的迭代器失效,但是其结构是红黑树,删除当前元素的,不会影响到下一个元素的迭代器,所以在调用erase之前,记录下一个元素的迭代器即可。
3.对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种正确的方法都可以使用
22、请你来说一下STL中迭代器的作用,有指针为何还要迭代器
Iterator(迭代器)模式又称Cursor(游标)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
迭代器不是指针,是类模板,表现的像指针。他只是模拟了指针的一些功能,通过重载了指针的一些操作符,->、*、++、–等。
迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用*取值后的值而不能直接输出其自身。
23、请你来说一下C++中struct和class的区别
这我倒是没有关注过。
class可以定义模板类形参,比如template <class T, int i>。
结构体(sturct)是一种值类型,而类(class)是引用类型。区别在于复制方式,值类型的数据是值赋值,引用类型的数据是引用复制。
结构体使用栈存储(Stack Allocation),而类使用堆存储(Heap Allocation)。
栈的空间相对较小.但是存储在栈中的数据访问效率相对较高;堆的空间相对较大.但是存储在堆中的数据的访问效率相对较低
结构体使用完之后就自动解除内存分配,类实例有垃圾回收机制来保证内存的回收处理 。
如何选择结构体还是类
1. 堆栈的空间有限,对于大量的逻辑的对象,创建类要比创建结构好一些
2. 结构体表示如点、矩形和颜色这样的轻量对象。
3. 在表现抽象和多级别的对象层次时,类是最好的选择,因为结构体不支持继承
4. 大多数情况下该类型只是一些数据时,结构体时最佳的选择
文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。
原文链接:lion-wu.blog.csdn.net/article/details/114575837