C++语法整理

1.C++中常使用cin、cout进行控制台的输入、输出

◼ cin用的右移运算符>>,cout用的是左移运算符<<
◼ endl是换行的意思

2.重载

◼ 规则
 函数名相同
 参数个数不同、参数类型不同、参数顺序不同

3.默认参数

◼ C++允许函数设置默认参数,在调用时可以根据情况省略实参。规则如下:
 默认参数只能按照右到左的顺序
 如果函数同时有声明、实现,默认参数只能放在函数声明中
 默认参数的值可以是常量、全局符号(全局变量、函数名

◼ 被extern "C"修饰的代码会按照C语言的方式去编译

◼ 如果函数同时有声明和实现,要让函数声明被extern "C"修饰,函数实现可以不修饰

4.内联函数

◼ 使用inline修饰函数的声明或者实现,可以使其变成内联函数
 建议声明和实现都增加inline修饰
◼ 特点
 编译器会将函数调用直接展开为函数体代码
 可以减少函数调用的开销
 会增大代码体积

◼ 注意
 尽量不要内联超过10行代码的函数
 有些函数即使声明为inline,也不一定会被编译器内联,比如递归函数

内联函数与宏

◼ 内联函数和宏,都可以减少函数调用的开销
◼ 对比宏,内联函数多了语法检测和函数特性
◼ 思考以下代码的区别
 #define sum(x) (x + x)
 inline int sum(int x) { return x + x; }
 int a = 10; sum(a++);

5.const

◼ const是常量的意思,被其修饰的变量不可修改
 如果修饰的是类、结构体(的指针),其成员也不可以更改

 const修饰的是其右边的内容,修饰以后均不能更改

6.引用(Reference)

◼ 在C语言中,使用指针(Pointer)可以间接获取、修改某个变量的值
◼ 在C++中,使用引用(Reference)可以起到跟指针类似的功能
◼ 注意点
 引用相当于是变量的别名(基本数据类型、枚举、结构体、类、指针、数组等,都可以有引用)
 对引用做计算,就是对引用所指向的变量做计算
 在定义的时候就必须初始化,一旦指向了某个变量,就不可以再改变,“从一而终”
 可以利用引用初始化另一个引用,相当于某个变量的多个别名
 不存在【引用的引用、指向引用的指针、引用数组】

引用的本质
◼ 引用的本质就是指针,只是编译器削弱了它的功能,所以引用就是弱化了的指针
◼ 一个引用占用一个指针的大小

7.常引用(Const Reference)

◼ 引用可以被const修饰,这样就无法通过引用修改数据了,可以称为常引用
 const必须写在&符号的左边,才能算是常引用
◼ const引用的特点
 可以指向临时数据(常量、表达式、函数返回值等)
 可以指向不同类型的数据
 作为函数参数时(此规则也适用于const指针)
✓ 可以接受const和非const实参(非const引用,只能接受非const实参)
✓ 可以跟非const引用构成重载
◼ 当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量

8.类

◼ C++中可以使用struct、class来定义一个类
◼ struct和class的区别
 struct的默认成员权限是public
 class的默认成员权限是private

9.this

◼ 可以利用this.m_age来访问成员变量么?
 不可以,因为this是指针,必须用this->m_age

10.内存空间的布局

◼ 每个应用都有自己独立的内存空间,其内存空间一般都有以下几大区域
 代码段(代码区)
✓ 用于存放代码


 数据段(全局区)
✓ 用于存放全局变量等


 栈空间
✓ 每调用一个函数就会给它分配一段连续的栈空间,等函数调用完毕后会自动回收这段栈空间
✓ 自动分配和回收


 堆空间
✓ 需要主动去申请和释放

 11.堆空间

◼ 在程序运行过程,为了能够自由控制内存的生命周期、大小,会经常使用堆空间的内存
◼ 堆空间的申请\释放
 malloc \ free
 new \ delete
 new [] \ delete []
◼ 注意
 申请堆空间成功后,会返回那一段内存空间的地址
 申请和释放必须是1对1的关系,不然可能会存在内存泄露
◼ 现在的很多高级编程语言不需要开发人员去管理内存(比如Java),屏蔽了很多内存细节,利弊同时存在
 利:提高开发效率,避免内存使用不当或泄露
 弊:不利于开发人员了解本质,永远停留在API调用和表层语法糖,对性能优化无从下手

12.堆空间的初始化

 13.对象的内存

◼ 对象的内存可以存在于3种地方
 全局区(数据段):全局变量
 栈空间:函数里面的局部变量
 堆空间:动态申请内存(malloc、new等)

13.构造函数

◼ 构造函数(也叫构造器),在对象创建的时候自动调用,一般用于完成对象的初始化工作
◼ 特点
 函数名与类同名,无返回值(void都不能写),可以有参数,可以重载,可以有多个构造函数
 一旦自定义了构造函数,必须用其中一个自定义的构造函数来初始化对象
◼ 注意
 通过malloc分配的对象不会调用构造函数

◼ 一个广为流传的、很多教程\书籍都推崇的错误结论:
 默认情况下,编译器会为每一个类生成空的无参的构造函数
 正确理解:在某些特定的情况下,编译器才会为类生成空的无参的构造函数
 

14.默认情况下,成员变量的初始化

15.析构函数(Destructor)

◼ 析构函数(也叫析构器),在对象销毁的时候自动调用,一般用于完成对象的清理工作
◼ 特点
 函数名以~开头,与类同名,无返回值(void都不能写),无参,不可以重载,有且只有一个析构函数
◼ 注意
 通过malloc分配的对象free的时候不会调用析构函数
◼ 构造函数、析构函数要声明为public,才能被外界正常使用

16.成员的访问权限

◼ 成员访问权限、继承方式有3种
 public:公共的,任何地方都可以访问(struct默认)
 protected:子类内部、当前类内部可以访问
 private:私有的,只有当前类内部可以访问(class默认)

◼ 子类内部访问父类成员的权限,是以下2项中权限最小的那个
 成员本身的访问权限
 上一级父类的继承方式

◼ 开发中用的最多的继承方式是public,这样能保留父类原来的成员访问权限
◼ 访问权限不影响对象的内存布局

16.初始化列表

◼ 特点
 一种便捷的初始化成员变量的方式
 只能用在构造函数中
 初始化顺序只跟成员变量的声明顺序有关
◼ 图片中的2种写法是等价的

 17.初始化列表与默认参数配合使用

◼ 如果函数声明和实现是分离的
 初始化列表只能写在函数的实现中
 默认参数只能写在函数的声明中

18.构造函数的互相调用

19. 父类的构造函数

◼ 子类的构造函数默认会调用父类的无参构造函数
◼ 如果子类的构造函数显式地调用了父类的有参构造函数,就不会再去默认调用父类的无参构造函数
◼ 如果父类缺少无参构造函数,子类的构造函数必须显式调用父类的有参构造函数

20.构造、析构顺序

 

 21.父类指针、子类指针

◼ 父类指针可以指向子类对象,是安全的,开发中经常用到(继承方式必须是public)
◼ 子类指针指向父类对象是不安全的

22.多态

◼ 默认情况下,编译器只会根据指针类型调用对应的函数,不存在多态
◼ 多态是面向对象非常重要的一个特性
 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
 在运行时,可以识别出真正的对象类型,调用对应子类中的函数
◼ 多态的要素
 子类重写父类的成员函数(override)
 父类指针指向子类对象
 利用父类指针调用重写的成员函数

23.虚函数

◼ C++中的多态通过虚函数(virtual function)来实现
◼ 虚函数:被virtual修饰的成员函数
◼ 只要在父类中声明为虚函数,子类中重写的函数也自动变成虚函数(也就是说子类中可以省略virtual关键字)

被虚函数声明的配合多态使用。

24.虚析构函数

◼ 如果存在父类指针指向子类对象的情况,应该将析构函数声明为虚函数(虚析构函数)
 delete父类指针时,才会调用子类的析构函数,保证析构的完整性

25.纯虚函数

◼ 纯虚函数:没有函数体且初始化为0的虚函数,用来定义接口规范
◼ 抽象类(Abstract Class)
 含有纯虚函数的类,不可以实例化(不可以创建对象)
 抽象类也可以包含非纯虚函数、成员变量
 如果父类是抽象类,子类没有完全重写纯虚函数,那么这个子类依然是抽象类

26.菱形继承

◼ 菱形继承带来的问题
 最底下子类从基类继承的成员变量冗余、重复
 最底下子类无法访问基类的成员,有二义性

27. 虚继承

◼ 虚继承可以解决菱形继承带来的问题
◼ Person类被称为虚基类

 

 28.静态成员(static)

◼ 静态成员:被static修饰的成员变量\函数
 可以通过对象(对象.静态成员)、对象指针(对象指针->静态成员)、类访问(类名::静态成员)
◼ 静态成员变量
 存储在数据段(全局区,类似于全局变量),整个程序运行过程中只有一份内存
 对比全局变量,它可以设定访问权限(public、protected、private),达到局部共享的目的
 必须初始化,必须在类外面初始化,初始化时不能带static,如果类的声明和实现分离(在实现.cpp中初始化)
◼ 静态成员函数
 内部不能使用this指针(this指针只能用在非静态成员函数内部)
 不能是虚函数(虚函数只能是非静态成员函数)
 内部不能访问非静态成员变量\函数,只能访问静态成员变量\函数
 非静态成员函数内部可以访问静态成员变量\函数
 构造函数、析构函数不能是静态
 当声明和实现分离时,实现部分不能带static

29.const成员

◼ const成员:被const修饰的成员变量、非静态成员函数
◼ const成员变量
 必须初始化(类内部初始化),可以在声明的时候直接初始化赋值
 非static的const成员变量还可以在初始化列表中初始化
◼ const成员函数(非静态)
 const关键字写在参数列表后面,函数的声明和实现都必须带const
 内部不能修改非static成员变量
 内部只能调用const成员函数、static成员函数
 非const成员函数可以调用const成员函数
 const成员函数和非const成员函数构成重载
 非const对象(指针)优先调用非const成员函数
 const对象(指针)只能调用const成员函数、static成员函数引用类型成员
◼ 引用类型成员变量必须初始化(不考虑static情况)

30.拷贝构造函数

◼ 拷贝构造函数是构造函数的一种
◼ 当利用已存在的对象创建一个新对象时(类似于拷贝),就会调用新对象的拷贝构造函数进行初始化
◼ 拷贝构造函数的格式是固定的,接收一个const引用作为参数

 ◼ car2、car3都是通过拷贝构造函数初始化的,car、car4是通过非拷贝构造函数初始化

◼ car4 = car3是一个赋值操作(默认是浅复制),并不会调用拷贝构造函数 

31.浅拷贝、深拷贝

◼ 编译器默认的提供的拷贝是浅拷贝(shallow copy)
 将一个对象中所有成员变量的值拷贝到另一个对象
 如果某个成员变量是个指针,只会拷贝指针中存储的地址值,并不会拷贝指针指向的内存空间
 可能会导致堆空间多次free的问题
◼ 如果需要实现深拷贝(deep copy),就需要自定义拷贝构造函数
 将指针类型的成员变量所指向的内存空间,拷贝到新的内存空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值