C++基础知识一

一、C++介绍
由本贾尼·斯特劳斯特卢普 于1979年4月份至1979年10月份开发一种语言,当时称为“C with Classes”(带类的C),
后来演化为C++。
C与C++区别:
1、C++完全兼容C语言的所有内容。
2、支持面向对象的编程思想(抽象、封装、继承、多态)。
3、支持运算符、函数重载。
4、支持泛型编程、模板。
5、支持异常处理。
6、类型检查严格。

二、第一个C++程序
1、文件扩展名:.cpp .cc .C .cxx
2、编译器:g++ 大多数的Linux系统需要额外安装。
sudo apt-get install g++
3、头文件:#include
#include <stdio.h> 可以继续使用
#include 但建议这样使用
4、输入输出
cout<< 标准输出
cin>> 标准输入(不需要取地址,因为C++中有引用)
cout/cin能自动识别数据类型,不需要占位符。
printf/scanf也可以继续使用。
注意:printf/scanf 是C标准库函数,cout/cin是C++标准库中类对象。
5、增加了名字空间
using namespace std;
练习1:输入n个整数,计算出最大值、最小值、平均值。

三、名字空间
名字空间:标识符的命名范围,就是把原本的全局空间进行拆分使用,形成一个个独立的命名空间,防止全局变量的命名冲突。
namespace 空间名{
// 定义变量
// 定义函数
// 设计新类型
}
注意:命名空间可以重名,同名的命名空间会自动合并(为了让声明和定义可以分开实现),同名命名空间中如果有同名标识符,依然会冲突。

如何使用命名空间:
    直接使用:
        :: 域限定符
        空间名::标识符,使用麻烦,但是安全。
    导入后使用:
        using namespace 空间名;
        使用方便,但依然有冲突的风险,相当于把垃圾分类型后又倒入同一个垃圾车。
匿名名字空间:
    也就是默认的全局空间,匿名空间中的标识符可以通过 ::标识符 访问,因此也就可能访问被屏蔽的全局的标识符。
    
名字空间嵌套:
    也就是名字空间中再定义名字空间,这种写法叫名字空间的嵌套。
    不同层次的空间中,可以重名,内层会自动屏蔽外层的标识符。
    namespace n1{
        int num;
        namespace n2
        {
            int num;
            namespace n3
            {
                int num;
            }
        }
    }
    在访问多层名字空间时需要逐层分解:
    n1::n2::n3::num;
名字空间取别名:
    多层空间使用比较麻烦,取别名可以简化该过程。
    namespace n123 = n1::n2::n3;

四、C与C++数据类型的区别
1、C++的结构
1、不再需要 typedef,在定义结构变量时,可以省略struct关键字。
2、成员可以是函数,在成员函数中可以直接访问结构成员,不再需要.或->,但必须通过结构变量或结构指针才能调用成员函数。
3、有一些隐藏的成员函数(构造、析构、拷贝构造、赋值构造)。
4、可以被继承,可以设置成员的访问权限(面向对象)。

2、C++的联合
    1、不再需要 typedef,可以省略 union 关键字。
    2、成员可以是函数,...
    3、有隐藏的成员函数,...
3、C++枚举
    1、不再需要 typedef,可以省略 enum 关键字。
    2、使用方法与C语言一致,但类型检查更严格,整型数据不能给枚举变量赋值。

4、C++布尔类型
    1、C++中有真正的布尔类型,bool是C++中的关键字。
    2、C++中true、false是关键字,而在C语言中是宏(用0或1替换)。
    3、C++中true、false占一个字节,在C语言中占4字节。

5、C++中的void*
    1、在C语言中void*可以与任何类型的变量自动转换(万能指针)。
    2、C++中void*类型的指针与不能给其它类型的指针变量赋值,但其它类型的指针可以给void*类型的指针赋值(为了兼容C语言)。
        void* p;
        int* p1 = p; // error
        p = p1; // ok
        int* ptr = (int*)malloc(4);
    C++为什么修改void*?
        为了更安全,C++的类型检查严格。
        C++可以自动识别数据类型(函数重载、模板),对于万能指针的需求再强烈。
6、C++中的字符串
    1、C++中字符串被封装成了string类,也可以转换成C语言中的字符串(c_str成员函数)。
    2、需要包含string头文件,但已经包含在iostream头文件中,属于std名字空间。
    3、常见的字符串操作不再需要函数,可以直接使用运行符。
        =  strcpy
        ==、!=、<=、>= strcmp
        += strcat
        size成员函数 strlen    

五、C++的内存管理
1、new/delete
C++中分配/释放堆内存的运行符,功能相当于C语言中的malloc/free
new 类型; //会自动计算字节数,然后从堆中分配相应的内存,然后返回一个带类型的指针。
delete 指针; //释放堆内存
new/delete 会自动调用类型中的构造函数和析构函数,而malloc/free不会。
注意:不能与C语言中的malloc/free混用,在C++中不建议使用malloc/free。
2、new[]/delete[]
new 类型[n]; 用于为数组分配内存,n是数组长度,会自动调用n次构造函数。
delete[] 指针; 专门释放数组内存,会调用n次析构函数,如果错用delete后果是不确定的。
new[] 所申请的内存的前4个字节,存储着数组的长度(仅限自定义类型)。
3、new/delete可能产生错误
1、new/new[]分配内存失败时不会返回NULL指针,而是抛出异常bad_alloc,如果不处理程序就会结束。
2、delete/delete[] 不能重复释放,否则会产生错误。
3、delete/delete[] 释放野指针后果不确定,释放空指针是安全的。
常考面试题:malloc/free与new/delete的比较?
不同点:
new/delete malloc/free
身份:运行符 函数
参数:类型 字节数
返回值:指针类型的地址 void*
析构/构造:自动调用 不调用
错误:抛异常 返回NULL
相同点:
1、管理堆内存。
2、不能重复释放。
3、可以释放空指针。

六、C++中和函数
1、函数重载
1、什么是函数重载
在同一个作用域下函数名相同而参数列表不同,即构成重载关系。
2、函数重载的机制
C++代码在编译时函数会把参数类型的缩写添加到函数名的末尾,最终生成的函数名并不相同,也就是C++的函数在编程过程中经历的换名的过程。

        注意:由于C代码在用gcc编译时不会经历换名,因此C++代码不能直接直接调用C编译器编译出的目标文件、库文件中函数,需要在函数声明时,extern "C" {} 包括一下。 
        extern "C" 作用让编译器按照C语言标准去查找并调用函数。

    3、重载和作用域
        同一作用域下的同名函数才构成重载关系,不同作用域(父子)下的同名函数构成隐藏关系。

    4、重载的解析过程
        当调用函数时,编译器会根据实参和形参的类型的匹配情况,选择一个确定的重载版本,这个过程叫重载解析。
        实参和形参的匹配情况有三种:
            1、找到最佳的匹配函数,编译器直接生成调用代码。
            2、找不到匹配函数,编译器将显示错误信息。
            3、找不到匹配函数,但实参过程类型提,有一个比较合适的,编译器将生成调用代码。
        二义性错误:编译器找到多个匹配函数,但没有最佳的,此时会产生二义性错误,这种错误解决方案是调整实参类型。
    5、确定重载函数的步骤
        1、候选函数
        函数调用的第一步就是确定所有的同名函数。
        2、选择可行性函数
        从候选函数中选择一个或多个函数,选择的标准是参数的个和类型。
        3、寻找最佳匹配
        优先选择完美的匹配方案,其次个数完全匹配,现其次考虑内字节数。
    6、const会影响重载
        参数是指针、引用类型是否用const修饰会影响重载结果。
    7、函数重载的优缺点
        优点:方便使用(不用取多个函数名,不用回调)
        缺点:可以引起编译编译错误(二义性),代码段会增大。
    
    注意:函数重载也是一种多态,它是在编译期间确定调用那个版本的函数,这种叫做编译时多态。
2、默认形参
    1、在C++中可以给函数的参数变量设置默认值,当调用这种函数,如果没有提供实参调用使用默认值。
    2、如果只有一部分参数设置默认形参数,那设置默认形参的参数必须连续且靠右。
    3、如果函数的声明和定义分开实现,那么只需要在声明时设置默认形参即可。
    4、函数的默认形参是在编译期间确定的,因此默认形参只能设置常量、表达式、全局变量。
    5、默认形参会影响函数重载,提高二义性的机率。
    注意:如果函数已经重载,尽量不要设置默认形参数。

3、内联函数
    1、普通函数在编译时生成二进制指令存在代码段中,调用函数时生成调用指令(跳转),
    然后执行到调用代码位置时跳转到函数所在的代码段中执行。
    2、把函数生成的二进制指令复制到函数的调用位置。
    3、优点:可以提高程序的运行速度(因为不需要跳转返回) 缺点:导致可执行文件增大(冗余),是一种典型用空间换取时间的做法。
    4、显示内联和隐式内联
        显示内联:在函数前加inine(C语言C99语法标准也可以使用)关键字。
        隐式内联:结构、联合、类中的内存部成员函数,这种函数会被编译器优化成内联函数。
    注意:inline对编译只有建议权,具体是否真正内联由编译器说了算。
    5、内联的机制与宏函数非常相像,具体的区别:
        函数                语句替换
        拷贝函数的二进制指令 展开宏函数代码
        传参                替换参数
        检查参数类型         不检查参数类型
        有返回值            只有执行结果
    6、内联适用条件
        由于内联会造成可执行文件变大,增加内存开销(占用代码段),因此只有同一次调用多次执行且内容简单的函数适合内联。
        调用次数少且复杂的函数,内联后不能显著提高速度,不足以抵消牺牲空间带来的损失。
        如果函数带有递归特性,则无法实施内联,编译器会忽略inline关键字。

七、引用
1、什么是引用
引用就是取别名,声明一个标识符与其它对象进行绑定,相当于一个对象对应多个名字。
2、什么时候适合使用
函数传参使用,与指针相比,它不需要额外空间,也不用赋值,仅仅内存与标识符的绑定,安全又高效、方便。
引用虽然很好,但并完全替代指针,如使用堆内存时仍然需要指针配合。
3、如何使用引用
int& 标识符 = 变量;
4、使用引用要注意的问题
1、定义引用时必须初始化,不存在空引用,但可能有悬空引用。
函数返回局部变量的引用,当函数执行完毕后,变量就会被销毁,此时返回的引用就叫悬空引用。
2、引用不能更改目标
引用一旦完成定义和初始化后,标识符就与普通变量一样,它就代表引用目标,一旦引用终生不能改变目标。
3、可以引用无名的临时对象,但必须使用常引用(相当于定义一个变量)。
4、如果引用的目标具备const属性,那么引用也必须带const。

练习2:实现一个C++版本的swap函数,配合函数重载适用于以下基本类型。
    char short int long float double
常用面试题:C++中的指针与引用的相同点和不同。
    相同点:函数之间共享变量(获取返回值),提高传参效率。
    不同点:
        取名机制                数据类型
        不需要额外的存储空间     需要4/8字节存储地址编号
        不能为空                可以为空
        映射关系                指向关系
        没有二级引用            有二级指针
        无法与堆配合            可以配合使用堆内存
        直接访问目标            需要解引用
        定义数组引用            可以定义数组指针
        不能定义引用数组        可以定义指针数组

八、强制类型转换
C语言的强制类型转换在C++中还可以继续使用,但是有安全隐患,建议使用C++的强制类型转换。
1、静态类型转换
static_cast<目标类型>(源类型);
两种类型至少有一个方向上能做隐式类型转换,否则报错。
2、去常类型转换
const_cast(目标类型)(源类型);
源类型和目标类型只胡const和非const的区别,只适用于指针和引用。
const int num;
int* p = const_cast<int*>(&num);
3、重解释类型
reinterpret_cast<目标类型>(源类型);
因为指针本质是一个整数,任何的整数类型都可以与指针类型进行转换,专用于指针类型与整型转换。
4、动态类型转换
dynamic_cast<目标类型>(源类型);
目标类型和源类型必须是指针或引用,源类型和目标类型之间存在继承关系。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值