C++的介绍

目录

一、函数重载

1、什么是函数重载?

2、C++是如何实现函数重载的

3、extern "C"

4、重载和隐藏

5、参数的类型转换

二、默认形参

1、什么是默认形参

2、默认参数要靠右

3、只能在函数声明处设置默认形参

4、默认形参可能会影响函数重载的效果

三、内联函数

1、普通函数

2、内联函数

3、显示内联和隐式内联

a. 显示内联:

b.隐式内联:

4、内联函数的使用条件

a. 内联的优点:

b. 内联的缺点:

c. 适用条件:

5、内联函数(inline)与宏函数(define)的相同点和不同点?

四、引用

1、什么是引用:

2、为什么要使用指针:

3、什么情况下适合用引用:

五、强制类型转换

1、为什么C++要重新设计新的强制类型转换?

2、为什么C++的强制类型转换设计的很复杂、使用很麻烦?

3、强制类型转换:

1、静态类型转换:

2、动态类型转换 :​

3、去常类型转换 ​:

4、重解释类型转换

六、面向对象与面向过程

面向过程:

面向对象: ​

1、抽象:

2、封装:

3、继承: ​

4、多态: ​

七、类和对象

1、什么是类和对象?

2、类的设计和实例化:

3、类的声明、定义和实例化:

1、在头文件中声明类

2、在源文件中定义类

3、实例化

八、访问控制限定符

九、构造函数

十、析构函数

十一、初始化列表


一、函数重载

1、什么是函数重载?

  • 在同一个作用域下,函数名相同、参数列表不同(参数个数和类型)的函数构成重载关系 ​
  • 函数重载与返回值类型、参数名无关

2、C++是如何实现函数重载的

  • 通过 g++ -S xxx.cpp 生成汇编代码得知,编译器会把函数的参数类型缩写后追加到函数名后面,也就是说编译时会给函数名进行换名

3、extern "C"

  • 因为C++编译器在编译函数调用语句时,会找换名后的函数调用,这样就无法调用到已经使用C编译器编译成功的函数了,使用extern ”C“ 会让C++编译器按照C编译器的格式来翻译函数名,这样函数的声明与定义就匹配,就可以正确地调用C标准库

4、重载和隐藏

  • 重载:在同一作用域下同名不同参地函数构成重载 ​
  • 隐藏:在不同作用域(父子类)下的同名函数遵循名字隐藏原则

5、参数的类型转换

  • 当调用函数时,编译器会优先调用类型最精确的函数,如果没有则会做一定程度的类型提升或者是标准转换,而不是全部直接报错,但具体优先级与编译器有关,因此最优选择最准确的参数即可,否则容易产生函数调用的二义性

二、默认形参

1、什么是默认形参

  • C++中可以给函数的参数设置默认值,当函数调用者提供了实参则使用实参,如果没有提供,则使用默认值

2、默认参数要靠右

  • 如果函数有多个参数,设置默认形参,必须遵循从右往左依次设置,否则有二义性
  • 3、只能在函数声明处设置默认形参

  • 如果函数声明与定义分开实现,只能在函数声明时设置默认形参,否则语法错误

4、默认形参可能会影响函数重载的效果

  • 如果对同名函数进行了重载,又设置了默认形参,则调用时可能会有冲突 ​ 因此未重载过的函数设置默认形参时一定要小心

三、内联函数

1、普通函数

  • 普通函数会被翻译成二进制指令存储在代码段中,调用语句会生成一句跳转指令,并让程序跳转到该函数所在代码段处运行,运行结束再返回

2、内联函数

  • 内联函数也会被翻译成二进制指令,调用语句不会生成跳转指令,而是直接把函数的二进制指令替换调用语句,这样既没有跳转也没有返回,而是直接往下执行被调函数,这种函数称为内联函数

3、显示内联和隐式内联

a. 显示内联:

在函数的返回值前面加 inline ,则该函数就以内联机制调用,但并不是所有编译器都支持内联机制,我们现在的g++ gcc 都不支持

b.隐式内联:

结构、联合、类中的成员函数会自动被当作内联函数处理

4、内联函数的使用条件

a. 内联的优点:

节约了函数的跳转、返回、传参的时间,提高了代码的运行速度

b. 内联的缺点:

当多处调用内联函数时,它的二进制指令会被拷贝多份,产生代码冗余,导致最终的可执行文件增大

c. 适用条件:

1、适合内容简单且一次调用多次执行的情况,因此不适合内容多且调用少的函数,因为这样节约的时间还弥补不了牺牲的内存 ​ 2、带有递归属性的函数无法内联,编译器会自动屏蔽inline关键字

5、内联函数(inline)与宏函数(define)的相同点和不同点?

四、引用

1、什么是引用:

引用是一种取别名的机制

2、为什么要使用指针:

a. 跨函数共享变量(输出型参数)时,引用可替代 ​ b. 提高了函数的传参效率 ,引用可替代,且效率高,引用不占字节 ​ c. 配合字符串时,string可以代替指针对字符串使用 ​ d. 配合堆内存使用,继续使用指针

3、什么情况下适合用引用:

1、跨函数共享变量时,引用比指针安全(不存在空引用、极少出现野引用)、引用比指针更方便(不用取地址,也不用解引用), ​ 2、提高传参效率,引用的传参效率比指针还高,因为指针还需要4\8字节用于存储内存地址,而引用一个字节都不需要,但是引用与指针一样有被修改的风险,因此为了安全需要加const保护一下

重点指针与引用的相同点与不同点: 相同点: 都可以跨函数共享变量、都可以提高函数的传参效率、也都需要const保护 不同点: 1、引用是一种取别名的机制,指针是一种数据类型 2、引用不需要额外的存储空间,而指针起码需要4\8字节内存用于存储内存地址编号 3、引用不能更换指向目标,而指针可以更改指向 4、引用必须初始化,而指针可以不初始化 5、有空指针,但没有空引用 6、指针可以配合堆内存使用,引用不可以 7、可以定义指针数组,但是不能定义引用数组(可以定义数组指针,也可以定义数组引用,可以定义函数指针,也可以定义函数引用)

五、强制类型转换

C语言中强制类型转换还能在C++中继续使用,因此C++中新的强制类型转换有点鸡肋

1、为什么C++要重新设计新的强制类型转换?

         因为C语言中的强制类型转换太危险

2、为什么C++的强制类型转换设计的很复杂、使用很麻烦?

        因为C++之父认为只有在程序设计不合理情况下,才需要进行强制类型转换,之所以设计负责就是不想让程序员使用,从而反思,重新设计自己的代码

3、强制类型转换:

1、静态类型转换:

  • static_cast<目标类型>(原数据) 目标类型与原数据类型之间必须有一个方向可以自动类型转换

2、动态类型转换 :​

  • dynamic_cast<目标类型>(源数据) 目标类型与原数据之间必须存在继承关系,否则会出现错误

3、去常类型转换 ​:

  • const_cast<目标类型>(源数据) ​ 目标类型与原数据类型必须是指针或引用,并且除了是否带const属性区别之外,其他类型都必须相同,否则出错

4、重解释类型转换

  • reinterpret_cast<目标类型>(源数据) 只能是把整数数据转换成指针、或者把指针转换成整数,否则出错

六、面向对象与面向过程

面向过程:

  • 关注的是如何解决问题、已经解决问题的步骤

面向对象: ​

1、抽象:

  • 先找出(想象出)能解决问题的"对象",分析该对象解决问题所需要的属性(成员变量)和行为(成员函数) ​

2、封装:

  • 把抽象的结果封装成一个类(结构),并给类的成员变量、成员函数设置相应的访问权(public/protected/private) ​

3、继承: ​

  • 1、在封装类之前,先考虑现有的类,是否有能解决一部分问题,如果有则把现有的类继承过来,在此基础上进行扩展,以此来节约解决问题的时间 ​
  • 2、把一个复杂的问题分析拆解成若干个小问题,每个问题设计一个类去解决,最后把这些类通过继承合并到一个能解决最终问题的类中 ​

4、多态: ​

  • 发出一个指令、系统会根据实际情况执行不同的相应的操作,这种特征称之为多态(同一命令多种形态) ​ 例如:重载过的函数,当调用函数时,编译器会根据参数的类型调用对应的重载版本,这就是一种多态,而且具体调用哪个版本,如果在编译时就能确定下来,这种重载被称为编译时多态

特别注意:面向对象的行为细节,本质上依然是面向过程,因此面向对象只是从更高的维度去思考解决问题,而不是寻求解决问题的捷径

七、类和对象

1、什么是类和对象?

类是由程序员自己设计的一种数据类型,它里面包含了成员变量和成员函数两部分 ​ 而对象是类的实例化,其实可以理解为使用类创建的变量

2、类的设计和实例化:

class 类型 ​

{ ​

        成员变量;

//类中成员默认属性是 private 私有 ​

public: ​

        成员函数; ​

}; ​

实例化: ​

方法1:类名 类对象名; ​

方法2:类名 *p = new 类型;

3、类的声明、定义和实例化:

1、在头文件中声明类

class 类型 {

        成员变量;

public:

        返回值 函数名(参数列表);

};//分号不能少

2、在源文件中定义类

返回值 类名::函数名(参数列表)

{

        //成员函数内可以直接使用成员变量,不用 . ->

}

注意:如果类的内容不多,可以考虑在头文件中全部实现出来

3、实例化

方法1: 类名 类对象名;

方法2: 类名* p = new 类型;

八、访问控制限定符

  • private 私有的,被它修饰的成员只能在类内访问,是类的默认访问属性
  • public 公开的,被它修饰的成员可以在任何位置访问,一般把类的成员函数设置为公开的
  • protected 保护的,被它修饰的成员可以在类内和子类中访问 注意:类不允许直接初始化成员

九、构造函数

构造函数是类的同名成员函数,没有返回值,当实例化对象时,它会自动执行,一般负责对类进行初始化、分配资源 class 类名 { int *p; public: 类名(参数); { p = new int; } };

  • 1、构造函数必须是public 否则无法实例化对象
  • 2、构造函数可以重载,可以有多个版本
  • 3、带参数的构造函数的调用方法: 类名 对象名(实参); 类名 对象指针 = new 类名(实参);
  • 4、默认情况下,编译器会自动生成一个无参构造函数,该函数什么都不做,一旦显示地实现了构造函数,则编译器不生成该函数 类名 对象名; //调用无参构造,如果没有无参构造,则报错
  • 5、也可以通过设置构造函数的默认形参达到无参构造的效果
  • 6、构造函数没有返回值
  • 7、不要使用malloc为类实例化对象分配内存,因为malloc不会调用构造函数

十、析构函数

析构函数负责对类对象进行收尾工作,例如:释放类中的资源、保存数据等,当类对象销毁时会自动调用执行

class 类名 { int *p; public: ​ 类名(参数) ​ { ​ p = new int; ​ } ~类名() { delete p; } };

  • 1、析构函数必须是public
  • 2、没有返回值、参数,不能重载
  • 3、当类对象生命周期完结、或者使用delete销毁对象时会自动调用析构函数
  • 4、如果没有显示的实现析构函数,编译器也会自动生成一个什么都不干的析构函数
  • 5、构造函数肯定会执行,析构函数不一定执行
  • 6、不要使用free来销毁对象,因为不会执行析构函数

十一、初始化列表

初始化列表是构造函数的一种特殊语法,只能在构造函数中使用

class 类名 { public; 类名(参数):成员名1(初始化数据),成员名2(初始化数据)... { //构造函数 } }

  • 1、类的成员变量载老编译标准中不可以设置初始值,而且在构造函数执行之前成员变量都已经定义完毕,因此const属性的成员变量无法在构造函数内正常赋值初始化(新标准中可以直接设置初始值,但是也只能给常量,功能有限)
  • 2、初始化列表先于构造函数执行的,初始化列表执行时类对象还没有构造完成,因此它是唯一(老标准)一种能给const属性成员变量赋值的方法
  • 3、当参数名与成员名相同时,初始化列表可以自动分辨成员名和参数名
  • 4、当类中有类类型成员时,该成员的有参构造函数也可以在初始化列表中被执
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值