C/C++面试中的高频考点

C/C++面试中的高频考点

      • 一、const
      • 二、智能指针
      • 三、类型转换关键字
      • 四、sturct和class的区别
      • 五、指针和引用的区别
      • 六、#include<>和#include" "的区别
      • 七、重载运算符的规则:
      • 八、内存四区
      • 九、关键字 volatile 在程序设计中有什么作用
      • 十、new/delete 与 malloc/free 的区别是什么?
      • 十一、深拷贝和浅拷贝的问题
      • 十二、野指针和空指针
      • 十三、虚函数和纯虚函数
      • 十四、菱形继承问题
      • 十五、sizeof和strlen的区别

一、const

1、const修饰变量称为:常量,表示该变量不可被修改;

const int a = 1; //a不可以被修改

2、const修饰指针有三种情况:
①、const修饰指针称为:常量指针指针指向可以改变,但是指针指向的值不可以改变

int a = 1;
int b = 1;
const int * p1 = &a; 
p1 = &b; //正确
//*p1 = 10;  报错

②、const修饰常量称为:指针常量定义时必须初始化,指针指向不可以改,指针指向的值可以更改

int a = 1;
int b = 1;
int * const p2 = &a;
//p2 = &b; //错误
*p2 = 10; //正确

③、const即修饰指针,又修饰常量,指针指向不可以改,指针指向的值也不可以更改

int a = 1;
int b = 1;
const int * const p3 = &a;
//p3 = &b; //错误
//*p3 = 10; //错误

辨别技巧:看const右侧紧跟着的是指针还是常量, 是指针就是常量指针,是常量就是指针常量。
3、常量引用
作用:常量引用主要用来修饰形参,防止误操作

//引用使用的场景,通常用来修饰形参
void showValue(const int& v) {
	//v += 10;
	cout << v << endl;
}
int main() {

	//int& ref = 1;  引用本身需要一个合法的内存空间,因此这行错误
	//加入const就可以了,编译器优化代码,int temp = 1; const int& ref = temp;
	const int& ref = 1;

	//ref = 100;  //加入const后不可以修改变量
	cout << ref << endl;

	//函数中利用常量引用防止误操作修改实参
	int a = 1;
	showValue(a);

	system("pause");

	return 0;
}

4、const修饰成员函数
常函数:
成员函数后加const后我们称为这个函数为常函数;
常函数内不可以修改成员属性;
成员属性声明加关键字mutable后,在常函数中依然可以修改
常对象:
声明对象前加const 称该对象为常对象;
常对象只能调用常函数。

class Person {
public:
	Person() {
		m_A = 10;
		m_B = 10;
	}

	//this指针的本质是一个指针常量,指针的指向不可修改
	//如果想让指针指向的值也不可以修改,需要声明常函数
	void ShowPerson() const {
		//const Type* const pointer;
		//this = NULL; //不能修改指针的指向 Person* const this;
		//this->mA = 1000; //但是this指针指向的对象的数据是可以修改的

		//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量
		this->m_B = 100;
	}

	void MyFunc() const {
		//mA = 10000;
	}

public:
	int m_A;
	mutable int m_B; //可修改 可变的
};


//const修饰对象  常对象
void test01() {

	const Person person; //常量对象  
	cout << person.m_A << endl;
	//person.mA = 100; //常对象不能修改成员变量的值,但是可以访问
	person.m_B = 100; //但是常对象可以修改mutable修饰成员变量

	//常对象访问成员函数
	person.MyFunc(); //常对象不能调用const的函数

}

二、智能指针

C++中的智能指针有auto_ptr、shared_ptr、weak_ptr、unique_ptr。智能指针其实就是对指针进行了封装,可以像普通指针一样使用,同时可以自行释放,避免忘记释放指针指向的内存地址造成内存泄漏的问题
auto_ptr:由 C++98 引入,定义在头文件 :memory中,是较早版本的智能指针,它在进行指针拷贝和赋值时,新指针直接接管旧指针的资源并且将旧指针指向为空,但是这种方式在需要访问旧指针时,就会出现问题;
unique_ptr:是auto_ptr的一个改良版本,不能赋值也不能拷贝,保证一个对象同一时间只有一个智能指针。
shared_ptr:可以使得一个对象可以有多个智能指针,当这个对象所有的智能指针被销毁时就会自动进行回收。
weak_ptr:是为了协助shared_ptr而出现的,它不能访问对象,只能观测shared_ptr的引用计数,防止出现死锁。

三、类型转换关键字

在 C++中,有哪 4 个与类型转换相关的关键字?这些关键字各有什么特点,应该在什么场合下使用?
在C++中,四个与类型转换相关的关键字:static_cast、const_cast、reinterpret_cast、dynamic_cast。
①、static_cast
特点:静态转换,在编译处理期间。
应用场合:主要用于C++中内置的基本数据类型之间的转换,但是没有运行时类型的检测来保证转换的安全性。
用于基类和子类之间的指针或引用之间的转换,这种转换把子类的指针或引用转换为基类表示是安全的;进行下行转换,把积累的指针或引用转换为子类表示时,由于没有进行动态类型检测,所以是不安全的。
把void类型的指针转换成目标类型的指针(不安全)。
不能用于两个不相关的类型转换。
不能把const对象转换成非const对象。
②、const_cast
特点:去常转换,编译时执行。
应用场合:const_cast操作不能在不同的种类间转换。相反,它仅仅把它作用的表达式转换成常量。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。
③、reinterpret_cast
特点: 重解释类型转换
应用场合:它有着和c风格强制类型转换同样的功能;它可以转化任何的内置数据类型为其他的类型,同时它也可以把任何类型的指针转化为其他的类型;它的机理是对二进制进行重新的解释,不会改变原来的格式。
④、dynamic_cast < type-id > ( expression )
该运算符将expression转换成type_id类型的对象。type_id必须是类的指针,类的引用或者空类型的指针。
  a、如果type_id是一个指针类型,那么expression也必须是一个指针类型,如果type_id是一个引用类型,那么expression也必须是一个引用类型。
  b、如果type_id是一个空类型的指针,在运行的时候,就会检测expression的实际类型,结果是一个由expression决定的指针类型。
  c、如果type_id不是空类型的指针,在运行的时候指向expression对象的指针能否可以转换成type_id类型的指针。
  d、在运行的时候决定真正的类型,如果向下转换是安全的,就返回一个转换后的指针,若不安全,则返回一个空指针。
  e、主要用于上下行之间的转换,也可以用于类之间的交叉转换。上行转换时和static_cast效果一样,下行转换时,具有检测功能,比static_cast更安全。

四、sturct和class的区别

①、使用struct时,它的默认访问权限是public(公共的),而class的默认访问权限是private(私有的);
②、struct的继承默认是public继承,而class的继承默认是private继承
③、class可以作模板,而struct不能。

五、指针和引用的区别

1、指针是一个新的变量,指向另一个变量的地址,我们可以通过访问这个地址来修改另一个变量;而引用时给变量起一个别名,对引用的操作就是对变量本身的操作;
2、指针可以有多级,但是引用只能由一级;
3、传参时,指针需要解引用(*)才能对参数进行修改,而引用可以直接对参数进行修改;
4、在32位系统中,指针的大小位4个字节,而引用的大小取决于变量的类型;
5、指针可以为空,引用不可为空,引用必须初始化,引用的本质就是一个指针常量

六、#include<>和#include" "的区别

#include<>直接从编译器制定的路径处搜索;
#include" " 先在程序当前目录中进行搜索,然后再从编译器制定的路径处搜索。

七、重载运算符的规则:

①、C++不允许用户字节定义新的运算符,只能对已有的C++运算符进行重载;
②、C++不能重载的运算符只有5个;
③、重载不能改变运算符运算对象的个数;
④、重载不能改变运算符的优先级和结合性;
⑤、重载运算符的函数不能有默认的参数;
⑥、重载的运算符必须和用户自定义类型的对象一起使用,至少应有一个是类对象,及不允许参数全部是C++的标准类型。

八、内存四区

代码区:存放函数体的二进制代码,由操作系统进行管理的;
全局区:存放全局变量和静态变量以及常量;
栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等;
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

九、关键字 volatile 在程序设计中有什么作用

volatile的英文意思是:脆弱的,它是一个类型修饰符,它用来修饰被不同线程访问和修改的变量,被volatile类型定义的变量,系统每次用到它的时候都是直接从对应的内存当中提取,而不会利用 cache 中的原有数值,以适应它的未知何时会发生变化,系统对这种变量的处理不会做优化。所有,volatile一般用于修饰多线程间被多个任务共享的变量和并行设备硬件寄存器,在嵌入式中用的非常多。

十、new/delete 与 malloc/free 的区别是什么?

在C++中,申请动态内存与释放动态内存,用new/delete 与 malloc/free都可以,而且他们的存储方式都相同,动态申请都位于堆区,无法被操作系统自动回收,因此需要手工回收,以免造成内存泄漏;
区别:
①、new能够自动计算需要分配的内存空间,而malloc需要手工计算字节数;
②、new和delete直接带具体类型的指针,而malloc与free返回void类型的指针;
③、new是类型安全的,而malloc不是;
④、new一般由两步构成,分别是new操作和调用构造函数,而malloc不能调用构造函数,delete将调用析构函数,而free不能。
malloc/free需要库文件stdlib.h支持,new/delete则不需要库文件支持。

十一、深拷贝和浅拷贝的问题

浅拷贝:简单的赋值拷贝操作;
深拷贝:在堆区重新申请空间,进行拷贝操作;
如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题,所以如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。

十二、野指针和空指针

野指针:①、是指指向不可用内存的指针,任何指针变量在被创建时,不会自动成为NULL指针,默认值是随机的,所以指针变量在创建的同时应当被初始化,或将指针设为NULL,或者让它指向合法的内存,而不应该放之不理,否则就会成为野指针。②、正是由于指针被释放(free或delete)后,没有将其设为NULL,导致该指针变为野指针;③、指针操作超越了变量的作用范围。
空指针:指针变量指向内存中编号为0的空间。
空指针和野指针都不是我们申请的空间,因此不要访问。

十三、虚函数和纯虚函数

用virtual修饰的函数就是虚函数。如果需要使用多态特性,就必须使用虚函数。
纯虚函数:在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容;因此可以将虚函数改为纯虚函数
纯虚函数语法:
virtual 返回值类型 函数名 (参数列表)= 0 ;
当类中有了纯虚函数,这个类也称为抽象类
抽象类特点:
①、无法实例化对象;
②、子类必须重写抽象类中的纯虚函数,否则也属于抽象类。

十四、菱形继承问题

菱形继承概念:
两个派生类继承同一个基类;又有某个类同时继承着两个派生类;这种继承被称为菱形继承,或者钻石继承
菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义;利用虚继承可以解决菱形继承问题

十五、sizeof和strlen的区别

①、sizeof是关键字,而strlen是函数;sizeof后如果是类型必须加(),如果是变量名可以不加();
②、sizeof操作符的结果类型是size_t,它在头文件中 typedef为unsigned int类型;该类型保证能够容纳实现所建立的最大对象的字节大小。
③、sizeof可以用类型作为参数strlen只能用char *做参数,而且必须是“\0”结尾,sizeof还可以以函数作为参数。

其他关于C++的文章:
C/C++中的高频考点二

你可能感兴趣的:(C/C++学习笔记,c++,面试,指针)