C++ 常用知识点(更新中)

c++的内存分为哪些区域

:栈区的内存空间由系统进行分配管理,常用于存储函数的形参、返回值以及局部变量。栈区从高地址向低地址扩展,是一块连续的内存区域,遵循FIFO原则,可读可写。

:由程序员管理,需要手动malloc/free new/delete进行分配以及释放。堆区从低地址向高地址扩展,空间相较栈区更大,同样遵循FIFO原则,可读可写。

全局/静态区:用于存储全局变量和静态变量,分为初始化和未初始化两个相邻区域。内存空间同样由系统管理,在程序运行结束时释放,可读可写。

文字常量区:存储常量,在程序运行结束时释放,只读。

代码区:存放程序的可执行二进制代码,只读。

c++的指针传递和引用传递有何区别

指针传递本质上是值传递,它传递的是一个地址值。值传递的过程中,被调函数的形参作为被调函数的局部变量处理,会在栈中开辟内存空间存放主调函数传入的实参,从而形成实参的一个副本。值传递的特点保证了被调函数对形参的任何操作都不会影响到主调函数的实参。

而引用传递虽然同样也是在栈中开辟了内存空间,但其存放的是主调函数传入实参的地址,此时被调函数对形参所做的任何操作可以被当作间接寻址,因此会影响到主调函数的实参。

static关键字的作用

1.修饰局部变量:局部变量在程序中存放在栈区内,它的生命周期将在其所属的语句块执行结束时结束。若对局部变量以static进行修饰,那么此时该变量将被存放至静态区,静态区的数据生命周期将持续到程序运行结束。需要注意的是,虽然局部变量的生命周期发生了改变,但其作用域并没有发生改变,依旧限制在所属的语句块内。

2.修饰全局变量/函数:通常对于一个全局变量/函数而言,它可以被同一工程内的所有文件所访问(需要添加extern声明)。对该变量/函数加以static修饰,那么作用域就从工程变为了当前文件内。

3.修饰类:在类中对某个函数进行static修饰,表示该函数属于类而不属于类的任何对象;如果是对类中的变量进行static修饰,表示该变量具有唯一性,可以通过类以及类的对象调用。

总结:在函数体内,static修饰的变量在函数体内值不可变;在模块内,static修饰的变量只能在模块内使用;在模块内,static修饰的函数只能被同一模块内的函数所调用;在类内,static修饰的变量没有this指针,通常在类内定义,类外声明;在类内,static修饰的函数只能访问静态数据成员,不能访问非静态数据。

const关键字的作用

1.用于定义常量,修饰基本数据类型。const修饰符可以用在类型说明符前,也可以用在类型说明符后。

2.修饰指针/引用变量,如果const位于*左侧,表示const修饰的是指针所指的内容,即常量指针;const位于*右侧,表示const修饰的是指针本身,即指针常量。

3.修饰类的成员函数,任何不会修改数据成员的函数都应用const修饰,以防止成员函数修改对象的内容。注意:const和static无法同时修饰成员函数,因为static修饰的成员函数不含this指针,无法实例化,而const成员函数又必须具体到某一个函数。注:如果确实需要修改const成员函数中的某一变量,可以用mutable修饰。

4.修饰类的成员变量,仅仅在类的某个对象中是常量,对于类而言,则可以是变量(因为类可以创建多个对象,不同对象的const数据成员可以不同)。注意:不能在类的声明中初始化const数据成员,类的对象还未创建,编译器无法确定const数据成员的具体值。const数据成员的初始化只能在类的构造函数的初始化列表中进行。

5.修饰函数形参,将值传递改为const&传递,可以提高效率,省去创建临时对象的过程。

void fun(A a);//通过值传递的方式传递,会产生临时对象用于复制a
void fun(A const &a);//引用传递不需要产生临时对象,但在函数体内可能会改变a,所以需要加const

const对象可以调用类中的const成员函数,不能调用非const成员函数;非const对象可以调用类中的const成员函数,也可以调用非const成员函数。

重载和重写

重载是指同一可访问区内被声明的几个具有不同参数列表的同名函数,可以是参数类型,个数,顺序的不同。

重写指子类重新定义父类中除了函数体外完全相同的虚函数。

智能指针

智能指针本质上是一个类,当超出自身的作用域时,会自动调用析构函数,因此相对于传统的指针,它不需要手动释放内存空间,可以有效的避免内存泄漏的情况。

auto_ptr :在c++11中已经被弃用。

unique_ptr:保证同一时间内只有一个智能指针可以指向该对象,常用于避免资源泄漏。

shared_ptr:多个智能指针可以指向相同对象,该对象和其相关资源会在最后一个引用被销毁时释放。可以通过成员函数use-count()来查看资源所有者个数。当调用release()来释放当前指针的所有权后,计数减一,当计数为0时,资源被释放。

weak_ptr:它指向一个shared_ptr管理的对象,用来解决在shared_ptr中的死锁问题,即两个shared_ptr互相引用,则两个指针的引用计数永远不为0,资源无法被释放。注:weak_ptr本身不会增加引用计数,可以与shared_ptr之间相互转化。

构造函数

类的对象被创建时,会自动调用构造函数完成一系列初始化工作。

无参构造函数:同默认构造函数,编译器自动生成的构造函数,函数内为空。也可以自己显示地写出一个无参构造函数。

一般构造函数:同重载构造函数,一个类可以有多个一般构造函数(参数列表不同),创建对象时会根据传入的参数列表选择对应的一般构造函数。

拷贝构造函数:拷贝构造函数的函数参数为对象本身的引用,常用于根据现有的对象复制一个新的对象,函数的传参或者函数的返回值。通常系统会默认创建一个拷贝构造函数(浅拷贝),当类中有指针成员时,建议手写一个拷贝构造函数(深拷贝),避免内存泄漏。

类型转换构造函数:分为显示转换和隐式转换两种,显示转换属于强制类型转换,具有一定风险。它只有一个参数,即需要转换的类型。

赋值运算符重载:类似于拷贝构造函数,区别在于赋值运算符重载是将被复制的对象值赋给原对象,即原对象是原本就存在的并非新构造的对象。

四种强制转换

static_cast:明确指出类型转换,如整型转浮点型、字符型转整型、不同类型指针之间的转换。常用于执行非多态的转换操作。

dynamic_cast:专门用于派生类之间的转换,可以将父类指针转换为子类指针,对于下行转换是安全的,当类型不一致时,转换过来的是空指针。

const_cast:专门用于增加const性质或去除const性质。

reinterpret_cast:从底层开始对数据进行重新解释,尽量避免使用,是一种高风险的转换。

指针和引用

指针:指向一块内存,本身是指向内存的地址,指针指向的内容可以修改,并且指针可以为空。

引用:是一块内存的别名,在定义时必须绑定在一块内存上,不能修改,且不能为空。

作为参数时,传指针等同于传值(指向内容的地址),传引用等同于传地址,因此传引用会导致原对象被修改而传指针不会(修改的是副本而不是本身)。

函数传参的方式

值传递:形参是实参的拷贝,函数内部对形参的操作并不会影响到外部的实参。

指针传递:与值传递相同,只不过传递的是地址,所以在函数内部的操作也不会影响到函数外部。

引用传递:传递的是地址,函数内部的任何操作都会影响函数外部的实参。

虚函数

当子类需要重写父类的方法,也就是实现多态过程,需要将父类中待重写方法定义为虚函数,即加上virtual关键字。当一个类含有虚函数时,编译器会为该类生成一个虚函数表,用来保存虚函数的地址。当程序员生成一个含有虚函数的类的对象时,编译器会生成一个虚函数指针指向该类的虚函数表(虚函数指针的初始化在构造函数中完成)。

同样地,一个子类继承了父类的虚函数,也会生成一个虚函数表。如果有一个父类指针指向子类,那么在调用虚函数时,会依据所指对象的虚函数表去调用虚函数,以此来实现多态。

注:析构函数一般要写成虚函数,降低内存泄漏的可能性。如果基类的析构函数没有定义成虚函数,那么编译器会根据指针类型认为当前对象为基类,调用基类的析构函数,导致派生类的内容无法被析构,造成内存泄漏。构造函数不能写成虚函数,因为虚函数需要通过对象的虚函数指针到虚函数表中调用,在执行构造函数时,对象还未生成,无法得到虚函数指针,因此无法调用虚函数。

纯虚函数

纯虚函数是为了让派生类只继承函数的接口,并且派生类必须对该纯虚函数进行实现,否则该派生类也只是一个抽象类,无法实例化。

声明格式:virtual 类型 函数名(参数列表)= 0

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值