C++语言学习01

发布时间 2023-08-25 21:01:54作者: 优秀还天籁

一、C++介绍
本贾尼.斯特劳斯特卢普,于1979年在贝尔实验室负责分析UNIX系统内核流量的分布情况时,特别希望有一种更加模块化的工具,
于1979年.10开始着手研发一款新的编程语言,在c语言的基础上增加了面向对象的机制,也就是C++,1983年完成了C++的第一个版本

C++与C的关联和重要区别:
1、C++完全兼容C语言的所有内容
2、支持面向对象的编程思想
3、支持运算符重载、函数重载的编译时多态机制
4、支持泛型编程、模版编程
5、支持异常处理
6、类型检查更加严格

注意:学习C++目前重点学习的是面向对象的编程思想,而不是各种花里胡哨的语法

二、第一个C++程序

#include <iostream>

using namespace std;

int main(int argc,const char* argv[])
{
    cout << "hello word!" << endl;
    return 0;
}
1、文件扩展名由 .c 变成 .cpp .cc .C .cxx

2、编译器由gcc变成了g++,gcc也可以继续使用,需要增加编译参数
    -xC++ -lstdc++

3、C++语言的标准头文件不带.h,iostream意为in out stream,在C++中输入、输出被封装成了流操作
c语言的头文件还可以继续使用,但是标准c的头文件建议名字换成前面加c,后缀去掉的新名字 例如 cstdio
为了删除原c标准头文件中的大量的宏,重新放入到名字空间中,防止命名冲突

4、C++输入输出
    cout    用于输出
    cin     用于输入
    输入输出不需要占位符,会自动识别数据类型
    printf/scanf 属于C标准库中的函数
    cout/cin    是C++标准库中的类对象
5、增加了名字空间机制,是C++为了解决命名冲突而发明的一项机制

三、C++与C数据类型不同
1、结构的不同
a、不再需要通过typedef来缩短结构类型名,在C++中设计好结构后,定义结构类型时,不再需要使用struct关键字了
b、结构中可以有成员是函数、成员变量,结构变量、结构指针使用'.'和'->'访问成员,如果是成员函数,那么可以直接访问
同结构中的任何成员,不需要'.'和'->'。
c、结构中有一些隐藏的成员函数:构造函数、析构函数、拷贝构造、赋值操作
d、结构可以继承其他结构,也可以被其他结构所继承
e、可以给成员赋予访问控制属性
public 公开的(默认)
protected 保护的(结构内和继承了它的结构中能使用)
private 私有的(只有结构中才能使用)
2、联合的不同
a、不再需要通过typedef来缩短联合类型名,在C++中设计好联合后,定义联合类型时,不再需要使用union关键字了
b、联合中可以有成员是函数、联合变量,联合变量、联合指针使用'.'和'->'访问成员,如果是成员函数,那么可以直接访问
同联合中的任何成员,不需要'.'和'->'。
c、联合中有一些隐藏的成员函数:构造函数、析构函数、拷贝构造、赋值操作
d、可以给成员赋予访问控制属性
public 公开的(默认)
protected 保护的(联合内中能使用)
private 私有的(只有联合中才能使用)

3、枚举的不同
    a、不再需要通过typedef来缩短枚举类型名,在C++中设计好枚举后,定义枚举类型时,不再需要使用enum关键字了
    b、C++编译器会对枚举的值进行检查,如果不符合就报错
    c、C语言使用整型来模拟的,而C++中的枚举类型是一种真正的数据类型,所以,不能与整型进行隐式类型转换了

4、布尔类型的不同
    a、C++中有真正的布尔类型,bool、true、false 是C++的关键字,不再需要包含stdbool.h头文件
    b、true、false 在C++中是1字节,而C语言是4字节(int)
    注意:无论是C还是C++,bool类型变量只能存储0或者1

5、字符串的不同
    a、C++中的字符串被封装成了 string 类,可以与C语言的字符串进行转换
    b、string类被封装在string 文件中,并属于std命名空间,但是string
    已经被iostream包含
    c、使用string类,可以通过运算符的方式直接操作字符串,但是c语言string.h
    中的str系列函数也可以继续使用
        =       strcpy
        +=      strcat
        ==      strcmp 相同为真
        size()\length()     strlen 只算字符个数
    d、C++中没有规定string类必须以字符'\0'作为结尾,编译器在实现时可以在结尾
    加上'\0'也可以不加,由编译器决定,因为string是一个类,它的长度信息已经被
    封装记录在私有成员变量中

6、void*的不同
    在c语言中,void*类型可以与任意类型指针进行自动转换
    在C++中,void*类型不可以自动转换成其他任意类型的指针,如果需要吧void*类型的指针
    赋值给其他类型的指针时,必须通过强制类型转换后才能赋值,为了提高指针数据类型的安全性
    但是其他类型的指针还是可以自动转换成void*类型的指针,因为C语言标准库中、系统函数中采用
    了大量的void*类型作为参数,如果不保留这个方式会导致C++在调用这些函数时非常麻烦
        int* p = (int*)malloc(4);

四、名字空间
1、为什么需要名字空间
由于C++完全兼容C语言,C++标准库中自带大量的类、函数、宏,而且支持继承语法,导致全局的标识符
大量增加,因此命名冲突的概率极大的增加,因为名字空间就是为了解决命名冲突
2、什么是名字空间
是C++中一种对命名空间进行逻辑划分的一种技术
namespace xxx
{
变量;
函数;
结构、联合、枚举;
类;
...
}
定义了名字空间后形成了一个相对封闭的作用域空间
3、如何使用
a、直接导入法
using namespace xxx;
之后就可以直接使用名字空间中的所有内容,虽然方便
实际工作中不建议
b、域限定符 ::
xxxx::标识符
4、名字空间可合并
名字空间可以被多次定义,不同位置的名字空间编译器会在编译时
自动合并
a.cpp
namespace n1 = {int a;}
b.cpp
namespace n1 = {int b;}
main.cpp
using namespace n1; //会把a、b都导入进来

5、名字空间中的声明和和定义可以分开
    a.h
    namespace n1{
        extern int num;
    }

    a.cpp
    int n1::num = 100;
    注意:可以分开定义,但是必须加上  名字空间名::变量名
6、匿名名字空间
    所有全局标识符都归属于同一个名字空间,称为匿名名字空间,可以通过
     ::全局标识符 来指定访问匿名名字空间中的内容
    例如:同名的全局变量被同名局部变量屏蔽后,可以以此指定访问全局变量

7、名字空间可以嵌套
namespace n1{ 
    int num = 10; 
    namespace n2{ 
        int num = 20; 
        namespace n3{ 
            int num = 30;   
        }
    }   
}
    采用逐层分解来访问
    n1::n2::n3::num

    导入指定层的名字空间
    using namespace n1::n2;

8、可以给名字空间的名字取别名
    namespace n123 = n1::n2::n3

五、C++的堆内存管理
1、C++中有专门用于管理堆内存的语句,而c语言中只能使用标准库提供的函数
语法格式:
类型* p = new 类型名;
new分配内存,相当于C语言中的malloc

    delete p;
        delete 释放内存,相当于C语言中的free

2、new允许在分配内存时直接初始化内存
    类型* p = new 类型名(val);
    int* p = new int(val);

3、new/delete不能与malloc/free 混合使用
    int* p = new int;
    free(p);
    虽然语法允许,但是不能这样混合使用,因为使用了new分配内存时,会自动调用
    结构、联合、类等类型的构造函数,使用delete释放内存时,会自动调用结构、联合
    类等类型的析构函数
    但是malloc和free都不会调用,如果混用,就会导致构造、析构没有对应调用

4、连续内存的申请和释放
    类型* p = new 类型名[个数];
        int* p = new int[10];   //有10个int类型的连续堆内存
        new[] 会多次的调用构造函数
    delete[] p;
        delete[]专门用于释放通过 new[]申请出来的内存
        delete[]也会多次调用析构函数
    注意:malloc/free new/delete new[]/delete[]  这些都是固定搭配,不能混用
    注意:通过new[]为结构、联合、类等类型申请的内存的前4字节中记录了申请的次数,这样
    就可以让编译器知道需要调用多少次构造函数和析构函数

5、重复释放问题
    delete可以释放空指针。但是也不能重复释放其他有效地址,与free一致

6、内存分配失败
    malloc分配内存失败会返回NULL
    new分配内存失败会爆出一个异常 std::bad_array_new_length,
    如果不接异常并处理,那么会终止
    
7、返回值类型不同
    malloc返回一个void*类型的指针
    new返回一个对应类型的指针

malloc/free 和 new/delete 的区别?
                    malloc/free        new/delete 
1、身份                 函数            运算符/关键字
2、返回值               void*           对应类型的指针
3、参数            字节个数(手动计算)    类型(自动计算)
4、连续内存         手动计算总字节数       new[个数]
5、扩容             realloc              无法直接处理
6、失败             返回NULL              抛异常
7、构造\析构:       不调用                 调用
8、初始化           不能初始化             可以初始化
9、头文件           stdlib.h              不需要
10、函数重载        不允许重载              允许重载
11、内存的分配位置    堆内存                自由存储区

注意:自由存储区是一个抽象的概念,而不是具体某个位置段,平时一般称new是分配在
堆内存也问题不大。因为new底层默认调用了malloc,所以此时称分配在堆内存没问题,
但是new可以像运算符一样被程序员重载或借助 new(地址) 类型 两种方式分配内存时,
可以分配到其他内存段,所以称为自由存储区