C++基础语言篇(一)
1. 说一下static关键字的作用
- 全局静态变量
- 全局变量就定义成全局静态变量
- 在静态存储区域,整个程序运行期间一直存在
- 会被自动初始化为0
- 作用域:在声明它的文件之外的是不可见的,从定义之处一直到文件结尾
- 局部静态变量
- 局部静态变量在静态存储区
- 自动初始化为0
- 作用域仍为局部作用域,当局部静态变量离开作用域时,并没销毁,仍然在内存当中,只不过不能对其进行访问,该函数再次被调用时,值不变
- 静态函数
- 函数的定义在默认情况下都是exterrn的,但只是在声明它的文件可见,不能被其他文件所用
- 函数的实现使用static修饰,那么这个函数只可在本cpp内使用,不会同其他cpp中的同名函数引起冲突
- 注意:不要再头文件中声明static的全局函数,不要在cpp内声明非static的全局函数,如果你要在多个cpp中复用该函数,就把它的声明提到头文件里去,否则cpp内部声明需加上static修饰;
- 类的静态成员
- 类中的静态成员可以实现多个对象之间的数据共享
- 对于多个对象来说,静态数据成员只存储一处,供所有对象共用
- 类的静态函数
- 对静态程序的引用可以不要对象名
- 在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员(这点非常重要)
- 调用使用命名空间调用
2. 说一下C++与C的区别
-
设计思想
面向对象与面向过程
-
语法上
- C++具有重载继承与多态
- C++相比C增加了许多类型安全的功能,比如强制类型转换
- C++支持泛型编程,模板类,模板函数
3、 说一下c++中四种cast转换
-
const_cast
将const变量转为非const
-
static_cast
用于各种隐式类型转换,比如非constz转const,void*转指针等,static_cast能用于多态向上转化,如果向下转能成功但是不安全,结果未知
-
dynamic_cast
用于动态类型转换。只能用于含有虚函数的类 ,用于类层次间的向上和向下转化。只能转指针或引用。向下转化时,如果是非法的对于指针返回NULL,对于引用抛异常。要深入了解内部转换的原理。
向上转换:指的是子类向基类的转换
向下转换:指的是基类向子类的转换
它通过判断在执行到该语句的时候变量的运行时类型和要转换的类型是否相同来判断是否能够进行向下转换。
-
reinterpret_cast
几乎什么都可以转,比如将int转指针,可能会出问题,尽量少用;
-
为什么不使用C的强制类型转换
C的强制转换表面上看起来功能强大什么都能转,但是转化不够明确,不能进行错误检查,容易出错。
4、 请说一下C/C++ 中指针和引用的区别?
- 指针有自己的一块空间,而引用只是别名
- 使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小;
- 指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象 的引用;
- 作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引 用的修改都会改变引用所指向的对象;
- 可以有const指针,但是没有const引用;
- 指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能 被改变;
- 指针可以有多级指针(**p),而引用至于一级
- 指针和引用使用++运算符的意义不一样;
- 如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄露。
5、 给定三角形ABC和一点P(x,y,z),判断点P是否在ABC内,给出思路并手写代码
面积法:根据面积法,如果P在三角形ABC内,那么三角形ABP的面积+三角形BCP的面积+三角形ACP的面积应该等于三角形ABC的面积
6、请你说一下你理解的c++中的smart pointer四个智能指针: shared_ptr,unique_ptr,weak_ptr,auto_ptr
为啥使用智能指针
- 申请空间忘记释放,内存泄漏
- 智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存
-
auto_ptr(C++98,C11弃用)
采用所有权模式
auto_ptr< string> p1 (new string ("I reigned lonely as a cloud.”)); auto_ptr<string> p2; p2 = p1; //auto_ptr不会报错.
此时不会报错,p2剥夺了p1的所有权,但是当程序运行时访问p1将会报错。所以auto_ptr的缺点是:存在潜在的内存崩溃问题!
-
unique_ptr(替换auto_ptr)
unique_ptr实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。它对于避免资源泄露(例如“以new创建对象后因为发生异常而忘记调用delete”)特别有用。
unique_ptr<string> p3 (new string ("auto")); //#4
unique_ptr<string> p4; //#5
p4 = p3;//此时会报错!!
unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1;// #1 not allowed
unique_ptr<string> pu3;//只是个临时的右值,允许这么做
pu3 = unique_ptr<string>(new string ("You")); // #2 allowed 调用的是构造函数,构造之后的临时对象会销毁
C++11中的移动语义,unique_ptr的赋值
unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;
-
shared_ptr
- shared_ptr实现共享式拥有概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。
-
weak_ptr
-
weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象
-
构造和析构并不会引起计数的增加和减小
-
用来解决share_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放
-
可以与share_ptr相互转换,可以直接赋值,可以调用lock捞获得shared_ptr
-
我们不能通过weak_ptr直接访问对象的方法,必须先转化为share_ptr
p = pa->pb.lock();
-
7、 怎么判断一个数是二的倍数,怎么求一个数中有几个1,说一下你的思路并手写代码
- 即判断该数的二进制的末尾是不是1
- 转化为unsigned int 然后与1相与
8、 指针和数组的区别
指针 | 数组 |
---|---|
保存数据的地址 | 保存数据 |
间接访问数据,首先获得指针的内容,然后将其作为地址,从该地址中提取数据 | 直接访问数据, |
通常用于动态的数据结构 | 通常用于固定数目且数据类型相同的元素 |
通过Malloc分配内存,free释放内存 | 隐式的分配和删除 |
通常指向匿名数据,操作匿名函数 | 自身即为数据名 |
9、请回答野指针是什么
野指针就是指向一个已删除的对象或者未申请访问受限内存区域的指针
10、请你回答智能指针有没有内存泄漏
两个对象相互使用一个share_ptr成员变量指向对方,会造成循环引用,使得引用计数失效,导致内存泄漏
11、 请你来说一下智能指针的内存泄漏如何解决
为了解决循环引用导致的内存泄漏,引入了weak_ptr弱指针,weak_ptr的构造函数不会修改引用计数的值,从而不会对对象的内存进行管理,其类似一个普通指针,但不指向引用计数的共享内存,但是其可以检测到所管理的对象是否已经被释放,从而避免非法访问。