C++学习笔记-----基础知识和常见面试问题

1.面向对象

        面向过程:以过程为中心,将程序抽象成数据和对数据的操作。

        面向对象:以对象(类)为中心,将程序抽象成对象之间的操作

1.1 封装、继承、多态

        封装:代码模块化;

        继承:代码重用;

        多态:接口重用。

1.2 重载和重写

重载:不同的函数使用相同的函数名,但是参数个数或者类型不同

重写:派生类中对基类的虚函数重新实现,即函数名和参数都一样,但是实现体不一样

1.3 深拷贝和浅拷贝

    浅拷贝:值拷贝,指向同一块内存空间,(默认构造函数和默认的赋值运算符重载函数)

    深拷贝:拷贝相应的内存,不会出现重复释放同一块内存的现象

1.4 多态:静态多态和动态多态

    静态多态有函数重载、运算符重载、泛型编程等,(重载和模板)

    动态多态是在程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数。当父类指针(引用)指向 父类对象时,就调用父类中定义的虚函数;即当父类指针(引用)指向 子类对象时,就调用子类中定义的虚函数(虚函数和继承)

1. 动态多态行为的表现效果为:同样的调用语句在实际运行时有多种不同的表现形态。

2. 实现动态多态的条件: - 要有继承关系 - 要有虚函数重写(被 virtual 声明的函数叫虚函数) - 要有父类指针(父类引用)指向子类对象

3. 动态多态的实现原理 当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储类虚函数指针的数据结构, 虚函数表是由编译器自动生成与维护的。virtual 成员函数会被编译器放入虚函数表中,存在虚函数时,每个对象中都有一个指向虚函数表的指针(vptr 指针)。在多态调用时, vptr 指针就会根据这个对象在对应类的虚函数表中查找被调用的函数,从而找到函数的入口地址(使用虚函数需要额外的内存和执行速度的成本)

1.5 拷贝构造和赋值构造

拷贝构造时机:用一个对象初始化另一个对象,对象以值传递的方式传递给函数参数,函数局部对象以值传递的方式从函数返回

赋值操作:将一个对象赋值给另一个对象

1.6 类如何不能实例化

1. 抽象类(纯虚函数)

2. 构造函数声明为private(单例模式)

1.7 多继承的二义性

1. 利用作用域::;

2. 派生类定义同名成员,覆盖基类的相关成员

3. 使用虚继承,使不同路径只有一份拷贝

1.8 指针数组和数组指针

数组指针 int (*p)[10];

指针数组  int *p[10]

2.不同数据类型的字节大小

不同的系统16位32位64位
char111
short222
int 244
float444
long448
longlong888
double81216
指针248

3.C++和C的区别

        1 C++兼容C

        2 C++是面向对象的语言,C是面向过程(主要区别,包括封装、继承、多态)

        3 C++可读性强,易于扩展、结构清晰

        4 C++效率高,仅比汇编慢10%~20%左右(例如算法题额外要求C++的执行时间更短)

        5 C++更安全,加入了类型转换、智能指针、try catch等

        6 C++可复用性高,引入了模板的概念,和标准模板库STL

        7 C++是在不断发展的语言,目前最新C++20

4.CONST详解(左定值右定向)

 4.1 用法

        4.1.1 用在变量上,使其值不能改变

        4.1.2 用在指针上,使其指向不能改变

        4.1.3 函数参数,说明函数体内参数不能修改

        4.1.4 类中修饰成员方法,防止在方法中修改非static成员

class A { public:  int a;  void fun() const {   a = 20; // 错误,const 
//修饰的成员方法中不能修改非静态成员变量  } }

        4.1.5 修饰类成员

 4.2 const常见问题

    const在变量的左边是定值,右边是定向(左定值右定向)

常量指针:

int a = 5;
const int *p =&a;
*p = 20;   //error  不可以通过修改所指向的变量的值

int b =20;
p = &b; //right  指针可以指向别的变量

指针常量:

int a = 5;
int *const p = &a;
*p = 20;     //right 可以修改所指向变量的值

int b = 10;
p = &b;      //error 不可以指向别的变量

5.函数指针

用法:①回调函数        ②代码量大时候的函数调用

6.delete和free

6.1 delete是操作符,free为函数

6.2 free不会调用析构函数,delete会

6.3 free之前需要检测指针是否为NULL,delete不需要

7.new和malloc区别

1. new是操作符,而malloc是函数。

2. new在调用的时候先分配内存,在调用构造函数,释放的时候调用析构函数;而malloc没有构造函数和析构函数。

3. malloc需要给定申请内存的大小,返回的指针需要强转;new会调用构造函数,不用指定内存的大小,返回指针不用强转。

4. new可以被重载;malloc不行

5. new分配内存更直接和安全。

6. new发生错误抛出异常,malloc返回null

8.引用和指针区别

引用和指针区别:

1. 指针是变量,存储地址,引用本质上是同一个变量,别名

2. 指针可以多级,引用一级;

3. 指针可以NULL,引用不行;

4. 指针可以改变指向,引用不行;

5. 把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,两者指向的地址相同,但不是同一个变量,在函数中改变这个变量的指向不影响实参,而引用却可以(改形参指向而不改其实参指向)

9.虚函数

虚函数可以是内联函数,但是不能在表现多态时候内联

9.1 纯虚函数

纯虚函数:特殊的虚函数,virtual int func(int a)=0;

            从而使该类变为抽象类,无法实例化,派生类需要重写才能实例化

9.2 虚函数和纯虚函数区别

            虚函数可以有实现,纯虚函数不能,且有返回值。

9.3 纯虚函数和虚函数作用

        虚函数作用:允许子类重新实现该功能;

        纯虚函数作用:让基类定义接口而不需要实现,确保派生类重写该函数,提供了一种强制规范。

9.4 纯虚析构函数的作用

        防止遗漏资源的释放,防止内存泄漏。如果基类中的析构函数没有声明为虚函数,基类指针指向派生类对象时,则当基类指针释放时不会调用派生类对象的析构函数,而是调用基类的析构函数,如果派生类析构函数中做了某些释放资源的操作,则这时就会造成内存泄露

10. define和typedef区别

typedef主要用于类型别名

1. define简单的字符串替换,没有类型检查,前者不是语句没有;

2. 预处理时处理,后者编译运行处理

3. 可以防止头文件重复引用,不分配内存,后者静态存储区分配内存,运行中程序有一个拷贝

11.内联函数和函数区别

1. 内联多了inline

2. 避免了函数调用的开销

3. 普通函数在被调用时,需要寻址,内联不需要

4. 内联函数要求代码简单

12.类型转换

1. static_cast 静态转换 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换

    - 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的 - 进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的 用于基本数据类型之间的转换,如把 int 转换成 char,把 char 转换成 int。这种转换的安全性也要开发人员来保证

2. dynamic_cast 动态转换 dynamic_cast 主要用于类层次间的上行转换和下行转换

    在类层次间进行上行转换时,dynamic_cast 和 static_cast 的效果是一样的 在进行下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全

3. const_cast 常量转换 该运算符用来修改类型的const属性 常量指针被转化成非常量指针,并且仍然指向原来的对象 常量引用被转换成非常量引用,并且仍然指向原来的对象 注意:不能直接对非指针和非引用的变量使用 const_cast 操作符

4. reinterpret_cast 重新解释转换 这是最不安全的一种转换机制,最有可能出问题 主要用于将一种数据类型从一种类型转换为另一种类型,它可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针

13.static关键字作用

    修饰局部变量时,使得该变量在静态存储区分配内存;只能在⾸次函数调⽤中进⾏⾸次初始化,之后的函数调⽤不再进⾏初始化;其⽣命周期与程序相同,但其作⽤域为局部作⽤域,并不能⼀直被访问;

    修饰全局变量时,使得该变量在静态存储区分配内存;在声明该变量的整个⽂件中都是可⻅的,⽽在⽂件外是不可⻅的;

    修饰函数时,在声明该函数的整个⽂件中都是可⻅的,⽽在⽂件外是不可⻅的,从⽽可以在多⼈协作时避免同名的函数冲突;

    修饰成员变量时,所有的对象都只维持⼀份拷⻉,可以实现不同对象间的数据共享;不需要实例化对象即可访问;不能在类内部初始化,⼀般在类外部初始化,并且初始化时不加 static ;

    修饰成员函数时,该函数不接受 this 指针,只能访问类的静态成员;不需要实例化对象即可访问。

简单来说就是:

1. 隐藏        2. 保持变量内容的持久        3. 默认初始化为0        4. 类中共享

14.智能指针

智能指针是⼀个RAII类模型,⽤于动态分配内存,其设计思想是将基本类型指针封装为(模板)类对象指针,并在离开作⽤域时调⽤析构函数,使⽤ delete 删除指针所指向的内存空间。

RAII手法:采用类封装,构造函数初始化指针,析构函数释放指针,使用时候由于初始化的类在栈上,所以当离开作用域时候会自动调用析构函数,从而释放其指向堆区的指针。

智能指针的作⽤是,能够处理内存泄漏问题和空悬指针问题。

三种智能指针:share、unique、weak、(atuo)

share(内部具有计数器,计数器到达0就释放)

15.悬挂指针和野指针

悬挂指针:指针指向的对象已经被释放,指针指向回收的地址

野指针:未初始化的指针

        避免:1.指针变量一定要初始化,可以初始化为 nullptr,因为 nullptr 明确表示空指针

                   2.释放后置为 nullptr

16. 动态链接和静态链接

1. 静态链接是在编译链接时直接将需要的执⾏代码拷⻉到调⽤处;

优点在于程序在发布时不需要依赖库,可以独⽴执⾏,缺点在于程序的体积会相对较⼤,⽽且如果静态库更新之后,所有可执⾏⽂件需要重新链接;

2. 动态链接是在编译时不直接拷⻉执⾏代码,⽽是通过记录⼀系列符号和参数,在程序运⾏或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运⾏到指定代码时,在共享执⾏内存中寻找已经加载的动态库可执⾏代码,实现运⾏时链接;

16.1 动态链接的优缺点

优点在于多个程序可以共享同⼀个动态库,节省资源;

缺点在于由于运⾏时加载,可能影响程序的前期执⾏性能

  • 29
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值