C++基础

基础语法

const的作用

1.修饰变量,说明该变量不可以被改变

2.修饰指针,分别指向常量的指针(const在*左边)和指针常量(const在*右边)

3.常量引用,经常用于形参类型,即避免了拷贝,又避免了函数对值的修改

4.修饰成员函数,说明该成员函数内不能修改成员变量

 

static的作用

1.修饰普通变量,修改变量的存储区域和生命周期,使变量存储在静态区,在main函数运行前就分配了空间,如果有初始值就用初始值初始化它,如果没有初始值系统用默认值初始化它

2.修饰普通函数,表面函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命令函数重名,可以将函数定位为static

3.修饰成员变量,修饰成员变量使所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员

4.修饰成员函数,修饰成员函数使得不需要生成对象就可以访问该函数,但是在static函数内不能访问非静态函数( 静态成员属于类而不是属于类对象,因此静态成员没有this指针)

 

#pragmapack(n)

设定结构体、联合以及类成员变量以n字节对齐

#pragmapack(push)//保存对齐状态
#pragmapack(4)//设定为4字节对齐
struct test
{
   charm1;
   doublem4;
   intm3;
};
#pragmapack(pop)//恢复对齐状态

 

volatile

  • volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器位置的因素(操作系统、硬件、其他线程等)更改。所以使用volatile告诉编译器不应对这样的对象进行优化
  • volatile关键字声明的变量,每次访问时都必须从内存中取出值(没有被volatile修饰的变量,可能由于编译器的优化,从CPU寄存器中取值)
  • const可以是volatile(如只读的寄存器状态)
  • 指针可以是volatile

 

extern"C"

  • 被extern限定的函数或者变量是extern类型的
  • extern"C"修饰的变量和函数是按照C语言方式编译和连接的

extern"C"的作用是让C++编译器将extern"C"声明的代码当作C语言代码处理,可以避免C++因符号修饰导致代码不能和C语言库中的符号进行连接的问题

#ifdef__cplusplus
extern"C"{
#endif
void*memset(void*,int,size_t);
#ifdef__cplusplus
}
#endif

 

C++ struct和class的区别

总的来说,struct更适合看成是一个数据结构的实现体,class更适合看成是一个对象的实现体

最本质的区别就是默认的访问控制

  1.默认的继承访问权限。struct是public的,class是private的

  2.struct作为数据结构的实现体,它默认的数据访问控制是public的,而class作为对象的实现体,它默认的成员变量访问控制是private的

  

explicit关键字

  • explicit关键字修饰构造函数时,可以防止隐式转换和复制初始化
  • explicit关键字修饰转换函数时,可以防止隐式转换,但是按语境转换除外

 

空类占用的内存大小

1个字节

 

智能指针

从比较简单的层面来看,智能指针是RAII(Resource Acquisition Is Initialization,资源获取即初始化)机制对普通指针进行的一层封装。这样使得智能指针的行为动作像一个指针,本质上却是一个对象,这样可以方便管理一个对象的生命周期。

 

auto_ptr:

是c++ 98定义的智能指针模板,其定义了管理指针的对象,可以将new 获得(直接或间接)的地址赋给这种对象。当对象过期时,其析构函数将使用delete 来释放内存

 

unique_ptr:

c++11取代auto_ptr,unique_ptr是独享被管理对象指针所有权(owership)的智能指针。unique_ptr对象封装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。

两个指针不能指向同一个资源,复制或赋值都会改变资源的所有权。

特性

  1. 基于排他所有权模式:两个指针不能指向同一个资源
  2. 无法进行左值unique_ptr复制构造,也无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值
  3. 保存指向某个对象的指针,当它本身离开作用域时会自动释放它指向的对象。
  4. 在容器中保存指针是安全的

 

shared_ptr:

它的原理是使用引用计数实现对同一块内存的多个引用。在最后一个引用被释放时,指向的内存才释放,这也是和 unique_ptr 最大的区别。当对象的所有权需要共享(share)时,share_ptr可以进行赋值拷贝。
shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。

在使用shared_ptr智能指针时,要注意避免对象交叉使用智能指针的情况! 否则会导致内存泄露!

 

weak_ptr:

weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。

同时weak_ptr 没有重载*和->但可以使用 lock 获得一个可用的 shared_ptr 对象。

在类中使用弱指针接管共享指针,在需要使用时就转换成共享指针去使用即可!

 

c++的四种类型转换

使用C风格的类型转换可以把想要的任何东西转换成我们需要的类型,但是这种类型转换太过松散,对于这种松散的情况,C++提供了更严格的类型转换,可以提供更好的控制转换过程,并添加4个类型转换运算符,使转换过程更规范:static_cast、dynamic_cast、const_cast、reinterpret_cast。

static_cast静态转换

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

o进行上行转换(把派生类的指针或引用转换成基类表示)是安全的

o进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的

用于基本数据类型之间的转换,如把int转换成char,把char转换成int。这种转换的安全性也要开发人员来保证

dynamic_cast动态转换

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

在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的

在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全

const_cast常量转换

该运算符用来修改类型的const属性

常量指针被转化成非常量指针,并且仍然指向原来的对象

常量引用被转换成非常量引用,并且仍然指向原来的对象

注意:不能直接对非指针和非引用的变量使用const_cast操作符

reinterpret_cast重新解释转换

这是最不安全的一种转换机制,最有可能出问题

主要用于将一种数据类型从一种类型转换为另一种类型,它可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针

 

c++中的内存对齐

主要就是struct的那一块。

对于32位来说默认四字节对齐

对于64位来说采用八字节对齐

 

简述一下C++从代码到可执行二进制文件的过程

标准回答:

c++从代码到可执行二进制文件经过四个过程,分别是:预编译、编译、汇编、连接

  1.预编译,主要的处理操作:

    a.将所有的#define删除,并且开展所有的宏定义(宏替换)

    b.处理所有的条件预编译指令,如#if、#ifdef

    c.处理#include预编译指令,将所包含的文件插入到该预编译指令的位置

    d.删除所有的注释

    e.添加行号和文件名标识

  2.编译:将于预处理之后的代码转换为特定的汇编代码,主要包括词法分析、语法分析、语义分析、优化代码等操作

  3.汇编:将汇编代码汇编成机器指令

  4.连接:将不同源文件生成的目标代码以及其他目标代码、库文件组合起来,从而形成可执行程序

加分回答:

  1.静态连接:静态连接是由连接器在连接时将库内容加入到可执行程序中,将一个或多个库和目标文件(先由编译器或汇编器生成)连接到一块可执行程序

  2.动态连接:动态连接在连接后动态库仍然与可执行文件分离,直到运行时才动态加载

 

面向对象

简述一下C++中的多态

标准回答

在现实生活中,多态是同一个事物在不同场景下的多种形态。在面向对象中,多态是通过基类的指针或者引用,在运行时动态调调用实际绑定的对象函数的行为,与之对应的编译时绑定函数称为静态绑定。所以多态分为静态多态和动态多态。

  1.静态多态  

  静态多态是编译器在编译时期完成的,编译器会根据参数类型来选择调用合适的函数,如果有合适的函数就调用,没有的话就会发出警告或者报错。静态多态有函数重载、运算符重载、泛型编程等。

  2.动态多态

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

加分回答

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

2.实现动态多态的条件:

  • 要有继承关系
  • 要有虚函数重写(被virtual声明的函数叫虚函数)
  • 要有父类指针(父类引用)指向子类对象

3.动态多态的实现原理

  当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储类虚函数指针的数据结构,虚函数表是由编译器自动生成和维护的。virtual成员函数会被编译器放入虚函数表中,存在虚函数时,每个对象都有一个指向虚函数表的指针(vptr指针)。在多态调用时,vptr指针就会根据这个对象对应类的虚函数表中查找被调用的函数,从而找到函数的入口地址。

 

说一说c++中哪些不能是虚函数

c++中,普通函数(非成员函数)、构造函数、友元函数、静态成员函数、内联成员函数 这些不能是虚函数。

1.普通函数(非成员函数)

  只有类的成员函数才能被声明为虚函数

  因为普通函数只能被重载,不能被重写。声明虚函数也没有什么意思,因此编译器会在编译时绑定函数。

 

2.构造函数

  构造函数时用来初始化对象的,虚函数的主要目的是实现多态,多条是依托于类的,多态的声明必须是对象创建之后。

  虚表指针的初始化是在构造函数中进行的,而虚函数要放到虚表中,在调用虚函数之前,要知道虚表指针,所以矛盾。

 

3.友元函数

  c++不支持友元函数的继承,所以不行。

 

4.静态成员函数

  静态成员函数理论是可继承的,但是是在编译时确定的,无法动态绑定,不支持动态,因此不能被重写,也不能声明为虚函数

 

5.内联成员函数

  内联函数必须有实体,在编译时在代码中直接展开,减少调用花费的代价。虚函数是为了继承后对象准确的执行自己的行为,这是不可能统一的。虚函数是在运行时才能动态绑定的函数。

 

总结:即不能被继承和不能被重写函数

 

虚函数表运行时加载在虚拟地址空间的哪里?

.rodata数据段

 

STL常用容器

STL中容器分为顺序容器、关联式容器、容器适配器三种类型,三种容器特性分别如下:

 

1.顺序容器

容器并非排序的,元素的插入位置同元素的值无关,包含vector、deque、list

 

vector:动态数组

元素在内存连续存放。随机存取任何元素都能在常数时间内完成。在尾端增删元素具有较佳的性能。

 

deque:双向队列

元素在内存连续存放,随机存取任何元素都能在常数时间内完成(仅次于vector)。在两端增删元素具有较佳性能(大部分是常数时间)。

 

list:双向链表

元素在内存不连续存放。在任何位置增删元素都能在常数时间内完成,不支持随机存取。

 

2.关联式容器

元素是排序的;插入任何元素,都按排序规则来确定位置;在查找时具有非常好的性能;通常以平衡二叉树的方式实现,包含set、multiset、map、multimap。

 

set/multiset

set中不允许相同元素,multiset允许存在相同元素

 

map/multimap

map与set的不同之处在于map中存放的元素有且仅有两个成员变量,分别是first、second,map根据first值对元素大小从小到大排序,并可以快速地根据first来检索元素。map和multimap的不同在于是否允许相同first值的元素。

 

3.容器适配器

封装了一些基本的容器,使之具备了新的函数功能,包含stack、queue、priority_queue

 

stack:栈

栈是项的有限序列,并满足序列中被删除、检索和修改的项只能是最近插入序列的项(栈顶元素),后进先出

 

quque:队列

插入只可以在尾部进行,删除、检索和修改只允许从头部进行,先进先出。

 

priority_queue:优先级队列

内部维持某种有序,然后确保优先级最高的元素总是位于头部,最高优先级元素总是第一个出列。

 

原文链接: https://www.cnblogs.com/wxk1213/p/16917764.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++基础

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/5102

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月4日 下午7:19
下一篇 2023年2月4日 下午7:19

相关推荐