1、static关键字的作用:
静态全局变量:在全局变量前加static,全局变量就变为全局静态变量;
静态存储区,在程序运行期间会一直存在;
未初始化的静态变量会自动初始化为0;
作用域为从定义处开始到文件结尾。
局部静态变量:在局部变量前加static关键字,局部变量就成为一个局部静态变量;
内存中也在静态存储区中;
没有初始化会被自动初始化为0;
作用域仍然为局部作用域当定义它的函数或者语句块结束时作用域结束,但是结束后局部静态变量还在内存中只不过不能继续访问,直到这个函数下次被调用且值不变。
静态函数:在函数返回值前加static,就定义为静态函数,静态函数只在声明他的文件中可见,不能被其他文件使用;
加static修饰该函数只能在本cpp内使用,不会同其他cpp中的同名函数引起冲突;
警告:不要在cpp内声明非static的全局函数,如果要在多个cpp中使用就把他的声明提到头文件中。
类的静态成员:在类中静态成员实现多个对象之间的数据共享,对多个对象来说,静态数据成员只存储一处供所有对象共同使用;
类的静态函数:对静态成员的引用不需要对象名;
在静态成员函数的实现中不能直接引用类中的非静态成员,要引用的话通过对象引用,调用静态成员函数可以用如下格式:<类名>::<静态成员函数名>(<参数表>)
2、c和c++的区别:
c++是面向对象的语言,而c是面向过程的语言;
c++具有封装、继承、多态三种特性;
c++相比于c,增加许多类型安全的功能,如强制类型转换;
c++可以范式编程,如模板类,函数模板。
3、c++中static关键字的作用:
对比一更加精简。对于函数定义和代码块之外的变量声明中,修改标识符的链接属性,这些符号只能在他们的源文件中使用;
对于代码块内部的变量声明,static改变其存储类型,由自动变量改为静态变量,作用域链接属性不变,在程序执行之前就创建,在整个程序执行周期都存在。
被static修饰的普通函数,只能在定义它的源文件中使用,不能在其他文件中引用;
static修饰的类成员变量和成员函数,他们是属于类的,不是某个对象,所有对象共享一个静态成员。
4、c++中四种cast转换:
const_cast:将const变量转变为非const;
static_cast:用于各种隐式转换,能用于多态向上转化,向下转化能成功但是不安全;
dynamic_cast:动态类型转换,只能用于含有虚函数的类,用于类层次空间的向上和向下转化,向上为子类向基类转,向下为基类向子类,只能转指针或者引用;
reinterpret_cast:几乎什么都可以转,但容易出问题。
5、为什么不用c的强制转换?
c的强制转换表面看起来什么都能转,但转化不够明确,不能进行错误检查,容易出错。
6、c/c++中指针和引用的区别(9条):
指针有自己的一块空间,引用只是一个别名;
使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小;
指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象的引用;
作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接引用的修改都会改变引用所指向的对象;
可以有const指针但没有const引用;
指针在使用中可以指向其他对象,但引用只能是一个对象的引用不能改变;
指针可以有多级指针,引用只有一级;
指针和引用使用++运算符的意义不一样;
返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄漏。
7、给定三角形ABC和一点P(x,y),判断点p是否在ABC内,思路加手写代码:
点p在三角形内则点p与其他三个点组成的三个三角形的面积之和等于三角形ABC的面积。
#include
#include <math.h>
using namespace std;
#define ABS_FLOAT 0.0001
typedef struct point {
float x;
float y;
}Point;
bool check(Point a, Point b, Point c,Point p) {
float first=square(a, b, c);
float second = square(a, b, p) + square(p, b, c)+square(a, p, c);
if ((-ABS_FLOAT <(first - second)) && ((first - second)<ABS_FLOAT))
return true;
else
return false;
}
float square(Point a, Point b, Point c) {
Point AB, AC;
AB.x = b.x - a.x; AB.y = b.y - a.y;
AC.x = c.x - a.x; AC.y = c.y - a.y;
return fabs((AB.x * AC.y + AB.y * AC.x) / 2);
}
8、你理解的c++中的smart pointer四个智能指针:auto_ptr、shared_ptr,unique_ptr、weak_ptr的理解:
四个智能指针auto_ptr、shared_ptr、unique_ptr、weak_ptr后三个c++11支持第一个已经被11弃用。
智能指针的作用是管理一个指针;申请的空间在函数结束时忘记释放,造成内存泄露,使用智能指针可以很大程度上避免这个问题;因为智能指针是一个类,当超出类的作用域时会自动调用析构函数释放资源。
auto_ptr当一个指针被剥夺所有权后访问该指针会报错,存在潜在的内存崩溃问题。
unique_ptr保证同一时间只有一个智能指针可以指向该对象
shared_ptr实现共享式拥有概念,多个智能指针可以指向同一对象,该对象会在“最后一个引用被销毁”时释放
weak_ptr是一种不控制对象生命周期的智能指针,它指向一个shared_ptr管理的对象,进行该对象的内存管理的是那个强引用的shared_ptr,weke_ptr只是提供了对管理对象的一个访问手段。解决shared_ptr相互引用时的死锁问题,
9、怎么判断一个数是二的倍数,怎么求一个数中有几个一,思路手写代码:
是否是二的倍数:该数的二进制末位是否是零,为零则是二的倍数,否则不是。
a%2== 0或者a&0x0001==0
int numberOf1(int num) {
int count = 0;
while (num) {
if(num % 10==1)
count++;
num = num / 10;
}
return count;
}
10、数组和指针的区别:
数组保存数据,指针保存数据地址;
指针间接访问数据,首先获得指针内容,然后以其为地址提取数据,数组直接访问数据;
指针常用于动态的数据结构,数组常用于数目固定且数据类型相同的元素;
指针通过Malloc分配内存,free释放内存,数组隐式分配和删除;
指针通常指向匿名数据,操作匿名函数,数组自身即为数据名。(记四条吧)
11、野指针是什么:
野指针就是指向一个已删除对象或者没有访问权限的内存区域的指针(后面这种就是指针没有初始化)。
12、介绍智能指针:
智能指针主要用于管理在堆上分配的内存,他将普通的指针封装成一个栈对象,当栈对象的生存周期结束后,会在析构函数中释放申请的内存,不能直接将普通指针赋值给智能指针,因为一个是类,一个是指针,可以通过构造函数传入普通指针。
13、回答智能指针有没有内存泄漏的情况:
当两个对象相互使用一个shared_ptr成员变量指向对方时,会造成循环引用,使引用计数失效,导致内存泄漏。
14、说一下智能指针内存泄漏如何解决:
用weak_ptr弱指针,weak_ptr不会对对象的内存进行管理,类似一个普通指针,不指向引用计数的共享内存,但可以检测到所管理的对象是否已经被释放,从而避免非法访问。
15、为什么析构函数必须是虚函数?为什么c++默认的析构函数不是虚函数:
将可能会被继承的父类的析构函数设置为虚函数,可以保证当new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类空间,防止内存泄露;
c++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外内存。对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此c++默认的析构函数不是虚函数,只有当需要作为父类时,设置为虚函数。
16、说一下函数指针:
函数指针是指向函数的指针,该指针指向一个具体的函数;
可以用该指针变量调用函数,也可以做函数的参数;
17、fork函数:
fork()函数作用是创建一个和当前进程映像一样的进程;
调用fork()会创建一个新的进程,几乎和调用他的进程一模一样,两个进程都会继续运行,在子进程中成功调用fork()会返回0,在父进程中则返回子进程的pid。出现错误返回一个负值;
最常见用法是创建一个新的进程,然后用exec()载入二进制映像,替换当前进程的映像。linux中采用写时复制,不是对父进程空间进程整体复制。
18、c++中析构函数的作用:
当对象结束生命周期,系统会自动执行析构函数;
析构函数名应与类名相同,在函数名前加一个位取反符~,不能带任何参数,也没有返回值,只有一个析构函数,不能重载;
若未编写析构函数,编译系统会自动生成一个缺省的析构函数,它不进行任何操作,所以很多简单类中没有析构函数;
类中有指针,且在使用过程中动态地申请了内存,最好显示构造析构函数在销毁类前,避免空间泄露。
19、静态函数和虚函数的区别:
静态函数在编译的时候就已经决定运行时机,虚函数在运行的时候动态绑定;虚函数用了虚函数表,调用时会增加一次内存开销。
20、重载和覆盖:
重载:两个函数名字相同,但是参数列表不同(个数,类型),返回值没有要求
覆盖:子类继承了父类,父类中的函数是虚函数,在子类中重新定义了这个虚函数,这叫重写。