c++面试总结(二)

目录

1.指针和引用区别

2.堆和栈的区别

3.delete 和 delete[]区别

4.类和结构体区别

5.多态的分类

6.const和static

7.智能指针总结

8.重写和重载

9.类型转换

10.TCP和UDP

11.进程  

12.STL

13.友元

14.this指针 

15.拷贝构造函数


1.指针和引用区别

引用只能在定义时被初始化一次,之后不可变;指针可变,可以改变所指的对象。

不存在指向空值的引用,但是存在指向空值的指针。

指针使用后需要删除,否则造成内存泄漏。

sizeof引用得到的是所指向的变量(对象)的大小,而sizeof指针得到的是指针本身的大小;

指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

作为参数时也不同,传指针的实质是传值,传递的值是指针的地址;传引⽤的实质是传地址,传递的是变量的地址

2.堆和栈的区别

People ren                  //栈分配内存
People ren = new People();  //堆区分配内存

对象占用内存大,需要在堆区分配内存;对象占用内存小,在栈分配内存。

堆区分配的内存需要手动释放,栈则不需要 ,因为栈中的对象是临时对象,其生命周期结束后会自动释放

3.delete 和 delete[]区别

delete 只调用一次析构函数,通常用于释放单个对象的堆空间;delete[]调用数组中每个元素的析构函数,用于释放对象数组的堆空间。

4.类和结构体区别

①类和结构体本身成员的默认访问级别不同,这是最本质的区别,结构体的成员和成员函数在默认情况下的访问级别是公有的(public),类的成员和成员函数在默认情况下的访问级别是私有的(private)。

②类和结构体的继承类的默认访问级别不同,前者是私有的,后者是共有的。

③赋值方式不同。

结构体赋值例如:(使用{}来对结构赋值)

struct A{char c1; int n2; float db3;};A a = {'a',1,3.14};

④C语言中的 struct 只能包含变量,而 C++ 中的 class 除了可以包含变量,还可以包含函数。 

5.多态的分类

多态分为静态多态和动态多态。静态多态是指在编译期间确定执行哪一个函数,通过重载同名函数运算符实现;动态多态是指在运行时确定执行哪个函数,通过虚函数实现。

6.const和static

const

① 修饰指针变量:

如果 const 位于 * 的左侧,则 const 就是⽤来修饰指针所指向的变量,即指针指向为常量

int const*a;
实际上可以看成是int const (*a),这表示指针a所指向的地址可以变,但是所指向的那个值不能变

int b = 3, c = 5;
int const *a = &b;
cout<<*a<<endl;     // 3
//*a = 6;       不能对*a进行修改,因为其值为const不可变
b = 6;          //但是可以用b来修改
cout<<*a<<endl;     // 6

如果 const 位于 * 的右侧,则 const 就是修饰指针本身,即指针本身是常量。

int *const a;
可以看成int* (const a);a的值其实是一个地址,这就表示a所保存的地址是不可以变的,但是这个地址对应的值是可以变的。

int b = 3, c = 5;
int *const a = &b;
//a = &c;		这一句是错的,因为a所指向的地址是不能变的
cout<<*a<<endl;     // 3
b = 6;
cout<<*a<<endl;     // 6

②const 修饰类对象,定义常量对象:常量对象只能调⽤常量函数,别的成员函数都不能调⽤。

static  

①修饰局部变量:⼀般情况下,对于局部变量在程序中是存放在栈区的,并且局部的⽣命周期在包含语句块执⾏结束时便结束了。但是如果⽤ static 关键字修饰的话,该变量便会存放在静态数据区,其⽣命周期会⼀直延续 到整个程序执⾏结束。

②修饰全部变量:对于⼀个全局变量,它既可以在本⽂件中被访问到,也可以在同⼀个⼯程中其它源⽂件被 访问(添加 extern进⾏声明即可)。⽤ static 对全局变量进⾏修饰改变了其作⽤域范围,由原来的整个⼯程可⻅变成 了本⽂件可⻅。

③修饰函数:情况和修饰全局变量类似,也是改变了函数的作⽤域。

④修饰:如果 C++ 中对类中的某个函数⽤ static 修饰,则表示该函数属于⼀个类⽽不是属于此类的任何特定对象;如果对类中的某个变量进⾏ static 修饰,则表示该变量以及所有的对象所有,存储空间中只存在⼀个副 本,可以通过类和对象去调⽤。

7.智能指针总结

为什么使用智能指针

智能指针其作⽤是管理⼀个指针,避免申请的空间在函数结束时忘记释放,造成内存泄漏。 使⽤智能指针可以很⼤程度上的避免这个问题,因为智能指针就是⼀个类,当超出了类的作⽤域类会⾃动调⽤析构函数,从而⾃动释放资源。

①unique_ptr

当需要独占资源的所有权的时候(即保证同一时间内只有一个智能指针可以指向该对象),可以使用 unique_ptr 对资源进行管理——离开 unique_ptr 对象的作用域时,会自动释放资源。

两个unique_ptr 不能指向一个对象,即 unique_ptr 不共享它所管理的对象。它无法复制到其他 unique_ptr,无法通过值传递到函数。

②shared_ptr

允许多个指针指向同一个对象。利用引用计数的方式实现了对所管理的对象的所有权的分享,即允许多个 shared_ptr 共同管理同一个对象,当引用计数为 0 的时候,自动释放资源。

③weak_ptr

share_ptr智能指针还是有内存泄露的情况:当两个对象相互使用一个shared_ptr成员变量指向对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。
weak_ptr 被设计为与 shared_ptr 共同工作,可以从一个 shared_ptr 或者另一个 weak_ptr 对象构造而来。weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,它更像是 shared_ptr 的一个助手而不是智能指针。

总结

如果程序要使用多个指向同一个对象的指针,应选择 shared_ptr

如果程序不需要多个指向同一个对象的指针,则可使用 unique_ptr。如果函数使用 new 分配内存,并返还指向该内存的指针,将其返回类型声明为 unique_ptr 是不错的选择。

为了解决 shared_ptr 的循环引用问题,使用 weak_ptr。

8.重写和重载

重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。

如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的方法名和参数类型和个数都和父类相同,那么子类的返回值类型必须和父类的相同。注意被重写的函数不能是 static 的, ⼀定要是虚函数,且其他⼀定要完全相同。

如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloading的方法是可以改变返回值的类型。也就是说,重载的返回值类型可以相同也可以不同。

9.类型转换

const_cast专⻔⽤于 const 属性的转换,去除 const 性质,或增加 const 性质, 是四个转换符中唯⼀⼀个 可以操作常量的转换符。

int num = 10;
const int* pNum = &num;
int* pNormalNum = const_cast<int*>(pNum);
*pNormalNum = 20;
cout<<"num:"<< num << endl;

static_cast用于各种隐式转换,明确指出类型转换,因为没有动态类型检查,向上转换 (派⽣类->基类)安全,向下转换(基类->派⽣类) 不安全,所以主要执⾏⾮多态的转换操作

Object obj;
obj.num = 6;
Base* pBase = &obj;     //子类对象转换为基类对象
// Base *pBase = static_cast<Base *>(&obj);   //将子类对象obj 转为基类指针pBase
cout<< "pBase:" << pBase->num<<endl

dynamic_cast用于动态类型的转换,只能用于含有虚函数的类;只能转指针或引用;向下转化时,如果是非法的对于指针返回NULL,对于引用抛bad_cast异常

reinterpret_cast:不到万不得已,不要使⽤这个转换符,⾼危操作。使⽤特点: 从底层对数据进⾏重新解 释,依赖具体的平台,可移植性差; 可以将整形转 换为指针,也可以把指针转换为数组;可以在指针和引⽤ 之间进⾏肆⽆忌惮的转换.

10.TCP和UDP

TCP(传输控制协议)是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。

一个TCP连接必须要经过三次“对话”才能建立起来简单的描述下这三次对话的简单过程:

1)主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;

2)主机B向主机A发送同意连接和要求同步 (同步就是两台主机一个在发送,一个在接收,协调工作)的数据包 :“可以,你什么时候发?”,这是第二次对话;

3)主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”, 这是第三次对话。

三次“对话”的目的是使数据包的发送和接收同步, 经过三次“对话”之后,主机A才向主机B正式发送数据。

关闭连接需要四次

UDP(用户数据报协议)是无连接的,尽最大可能交付,没有拥塞控制,面向报文,支持一对一、一对多、多对一和多对多的交互通信。

七层网络模型分别是:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。

11.进程  

 进程有运⾏、阻塞、就绪三个基本状态。

① 进程是指在系统中正在运⾏的⼀个应⽤程序,程序⼀旦运⾏就是进程;

② 进程可以认为是程序执⾏的⼀个实例,进程是系统进⾏资源分配的最⼩单位,且每个进程拥有独⽴的地址空间;

③ ⼀个进程⽆法直接访问另⼀个进程的变量和数据结构,如果希望⼀个进程去访问另⼀个进程的资源,需要使⽤进程间的通信,⽐如:管道、消息队列、信号量和共享内存

④线程是进程的⼀个实体,是进程的⼀条执⾏路径;⽐进程更⼩的独⽴运⾏的基本单位,线程也被称为轻量级进程,⼀个程序⾄少有⼀个进程,⼀个进程⾄少有⼀个线程。

进程和线程区别

①同⼀进程的线程共享本进程的地址空间,⽽进程之间则是独⽴的地址空间

②同⼀进程内的线程共享本进程的资源,但是进程之间的资源是独⽴的

③⼀个进程崩溃后,在保护模式下不会对其他进程产⽣影响,但是⼀个线程崩溃整个进程崩溃,所以多进程⽐多线程健壮

④进程切换,消耗的资源⼤。所以涉及到频繁的切换,使⽤线程要好于进程;

两者均可并发执⾏

⑥每个独⽴的进程有⼀个程序的⼊⼝、程序出⼝。但是线程不能独⽴执⾏,必须依存在应⽤程序中,由应⽤程序提 供多个线程执⾏控制

死锁 是指多个进程循环等待它⽅占有的资源⽽⽆限期地僵持下去的局⾯。很显然,如果没有外⼒的作⽤,那么死锁涉及到的各个进程都将永远处于封锁状态。当两个或两个以上的进程同时对多个互斥资源提出使⽤要求时, 有可能导致死锁。

12.STL

序列式容器

①vector 动态数组

在内存中分配⼀块连续的内存空间进⾏存,可以像数组⼀样操作,动态扩容,随机访问(O(1));在频率较⾼的插⼊和删除时效率比较低。

②list 双向链表,每个结点都包含⼀个数据域data、⼀个前驱指针 prev 和⼀个后驱指针 next。

进⾏插⼊删除效率高,但不支持随机访问,相对于vector占用内存多。

③deque 双向队列

随机访问⽅便,插⼊和删除操作效率高; 可在两端进⾏ push、pop;但是因为涉及⽐较复杂,采⽤分段连续空间,所以占⽤内存相对多

总结

1、如果你需要⾼效的随即存取,⽽不在乎插⼊和删除的效率,使⽤ vector。

2、如果你需要⼤量的插⼊和删除,⽽不关⼼随机存取,则应使⽤ list。

3、如果你需要随机存取,⽽且关⼼两端数据的插⼊和删除,则应使⽤ deque

以 deque 为底层容器的适配器  stack(栈)和 queue(队列)

关联式容器

序列式和关联式容器的本质区别在于:序列式容器是通过元素在容器中的位置顺序存储和访问元素,⽽关联容器则是通过键 (key) 存储和读取元素。

关联式容器从底层实现分为两类:①红黑树:set、map、multiset和multimap ②哈希:unordered_set、unordered_map、unordered_multiset和unordered_multimap。

13.友元

友元的目的 是让一个函数或者类 访问另一个类中的私有成员

14.this指针 

this 是一个 const指针,它指向当前对象,通过它可以访问当前对象的所有成员。当前对象是指正在使用的对象。例如对于stu.show();,stu 就是当前对象,this 就指向 stu。

this 只能用在类的内部,通过 this 可以访问类的所有成员。this 虽然用在类的内部,但是只有在对象被创建以后才会给 this 赋值,并且这个赋值的过程是编译器自动完成的,不需要用户干预,用户也不能显式地给 this 赋值。

15.拷贝构造函数

class Student{
public:
    Student(string name = "", int age = 0, float score = 0.0f);  //普通构造函数
    Student(const Student &stu);  //拷贝构造函数(声明)

private:
    string m_name;
    int m_age;
    float m_score;
};

//拷贝构造函数(定义)
Student::Student(const Student &stu){
    this->m_name = stu.m_name;
    this->m_age = stu.m_age;
    this->m_score = stu.m_score;
}

拷贝构造函数只有一个参数,它的类型是当前类的引用,而且一般都是 const 引用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值