C++记录总结及面试常见问题

指针和函数

函数值传递会拷贝变量副本,增加内存空间,函数内部改变变量值不影响主函数(函数外部)的变量值。
函数指针传递不会拷贝变量副本,并且指针变量占用首字节固定,不会增加占用内存空间,改变函数内部参数值在函数外部也会改变。若本意不想修改函数内部的数据或者防止误操作,可以传递一个const 指针。
func(int a, int b)值传递,形参不会修饰实参
func(int *a, int *b)地址传递,形参会修饰实参
func(int& a, int& b)引用传递,形参会修饰实参,若不想修改,可以在形参前加const

内存分区模型

程序运行前:
代码区:存放函数体的二进制代码,由操作系统进行管理的。共享+只读特点。
全局区:存放全局变量和静态变量及常量
程序运行后:
栈区:由编译器自动分配释放,存放函数的参数值,局部变量等。不能返回局部变量地址,第一次保留第二次会释放乱码。
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。利用new关键字可以将数据开辟内存到堆区,手动开辟,手动释放,关键字为delete,若为数组加[] 即delete[]
不同区域存放的数据,赋予不同的生命周期,具有更大的灵活编程。

访问权限

public 成员 类内可以访问,类外可以访问
protected 类内可以访问,类外不可以访问, 子类可以访问
private 类内可以访问,类外不可以访问,子类不可以访问
成员属性/变量,设为私有,可以自己控制读写权限,可以检测数据有效性。可以通过公共成员函数去设置读或者写操作。

struct & class创建类

struct 默认公共权限
class 默认私有权限

构造函数

参数分:有参构造、无参构造(默认构造)
类型分:普通构造、拷贝构造 将传入的属性拷贝到自己身上用法:(类名(const 类名 &属性)),注意,不能用拷贝构造,初始化为匿名对象,会重定义。
调用默认构造不加(),若加()编译器会认为是一个函数的声明。
调用方式:1.括号法,也是匿名对象,当前行执行结束后会立即回收匿名对象(调用析构)2、显示法,用括号法在赋值给左参方式,3、隐式调用有参构造,直接=赋值到左参。

静态成员

包括静态成员变量和静态成员函数
静态成员变量:
1、所有对象共享一份数据
2、在编译阶段分配内存
3、类内声明,类外初始化
有两种访问方式:通过对象访问,通过类名访问
静态成员函数:
1、所有对象共享一个函数
2、只能访问静态成员变量

this指针

this指针指向被调用的成员函数所属的对象。
隐含每一个非静态成员函数内的一种指针。
不需要定义,直接使用即可。
用途:
当形参和成员变量同名时,可以用this指针来区分。类似python中的self
在类的非静态成员函数中返回对象本身,用return *this

const 修饰成员函数

称为常函数,常函数内不可以修改成员属性。(this指针的本质是指针常量,指针的指向不可以修改)
若想修改,可以在成员属性声明加关键字mutable
若声明对象前加const,则为常对象。
常对象只能调用常函数。

友元friend

目的是让一个函数或者类访问另一个类中私有成员。
1、全局函数做友元
2、类做友元
3、成员函数做友元

重载运算符和重载函数

C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。
对内置数据类型的表达式运算符是不可以改变的

继承

语法:class子类(派生类):继承方式 父类(基类)
好处:减少重复代码
在这里插入图片描述

在这里插入图片描述

读文件ifstream/fstream

前三种是按行读取,第四种是单个字符读取效率最低,前两种是c语言的字符数组代表一个字符串,第三种是C++string代表字符串。
在这里插入图片描述

vector中resize和reserve的区别

1.capacity在容器初始化时赋值,指容器能够容纳的最大元素个数,此时容器中还没有创建对象,不能通过下标等访问。
2.size指容器中实际的元素个数,可以通过下标访问。
resize既分配内存空间也创建对象。即修改了capacity大小也修改size大小。
reserve只修改capacity的大小,不能修改size大小。

智能指针

shared_ptr、unique_ptr、weak_ptr
shared_ptr:引用计数是存放在堆上,允许多个指针指向同一个对象
unique_ptr:独占所指向的对象,不能将一个unique_ptr指向的对象赋值给另一个unique_ptr。没有引用计数,性能好于shared_ptr
wear_ptr:是一个不控制所指向对象生存期的智能指针,指向由shared_ptr管理的对象。

左值与右值

可以取地址的,有名字的,非临时的就是左值。
不能取地址没有名字临时的,通常生命周期在某个表达式之内的就是右值。

引用

对象的别名,即对象本身,修改形参会改变实参本身。
不能使一个引用重新指向另一个对象
尽可能使用引用,不得已使用指针

宏定义 & const区别

(1) 编译器处理方式不同

  • define宏是在预处理阶段展开。
  • const常量是编译运行阶段使用。

(2) 类型和安全检查不同
const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。

  • define宏没有类型,不做任何类型检查,仅仅是展开。
  • const常量有具体的类型,在编译阶段会执行类型检查。

(3) 存储方式不同

  • define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。

  • const常量会在内存中分配(可以是堆中也可以是栈中)。

(4) const 可以节省空间,避免不必要的内存分配。
(5) 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。

string & char转换

一、string转char*。

主要有三种方法可以将str转换为char*类型,分别是:data(); c_str(); copy();
1.data()方法,如:

string str = "hello";
const char* p = str.data();//加const  或者用char * p=(char*)str.data();的形式

2.c_str()方法,如:

1 string str=“world”;
2 const char *p = str.c_str();//同上,要加const或者等号右边用char*

3.copy()方法,如:

1 string str="hmmm";
2 char p[50];
3 str.copy(p, 5, 0);//这里5代表复制几个字符,0代表复制的位置,
4 *(p+5)=‘\0;//注意手动加结束符!!!

二、char * 转string。

可以直接赋值。

1 string s;
2 char *p = "hello";//直接赋值
3 s = p;

push_back & emplace_back

emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。
push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);
而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程

指针常量&常量指针

常量指针(指针):(指向常量的)指针。

int a = 10;
int b = 20;
const int* p1 = NULL;
p1 = &a;
// 指针p1所指向的变量是一个常量,即指针p1在解引用时,值不能改变
p1 = 20;在这里插入代码片

指针常量(常量):(指针本身是一个)常量。

// 指针常量
int const p2 = &a;
// 指针只能指向a的地址,a的值可以改变,指针p2已经指向了a的地址,所以不能指向b;
p2 = &b;

也可以这样理解:直接看const 关键字的位置如下:
常量指针:

const int p1 = nullptr;或者 int const * p1 = nullptr;

指针常量:

int* const p2 = nullptr;

猜你喜欢

转载自blog.csdn.net/qq_39506862/article/details/129699029