C++基础知识

  1. 单行注释 //
    多行注释 /**/
  2. 常量
    #define 常量名 常量值
    const 数据类型 常量名 = 常量值
  3. 关键字不要和变量或常量重名
  4. 数据类型
  • 短整型(2字节)-整型(4字节)-长整型(4字节)-长长整型(8字节)
    short<int<=long<=long long
    实型
  • float(4)-double(8)
  • 科学计数法
    3e2 3*10^2
    3e-2 3*0.1^2
  1. sizeof
    sizeof(datatype\变量)
  2. 字符型
    char ch = 'a'
    字符串
    C风格char str[] = "abc"
    C++风格 string str = "abc"
  3. 布尔型
    bool flag = true
  4. 键入
int a = 0;
cin >> a;
float b = 3.14f;
cin >> b;
char ch = 'a';
cin >> ch;
string str = "hello";
cin >> str;
bool flag = true;
cin >> flag;
  1. 三目运算符
    表达式1 ?表达式2 : 表达式3
    返回的是变量,可以继续进行赋值操作
  2. goto 无条件跳转语句
  3. 二维数组定义时可以省去行数
  4. 查看二维数组的首地址 (int)arr
    二维数组的第一行首地址 (int)arr[0]
    二维数组第一个元素的首地址 (int)&arr[0][0]
    int 不是必须加的。只是转换类型
  5. 值传递 形参改变不会改变实参
    地址传递 传递的是地址,实参可以改变
  6. 函数的声明
    无需在main前定义函数 int max(int a, int b);
    声明可以多次,定义只有一次
  7. 函数的分文件编写
    头文件声明函数
    源文件导入头文件 应用函数
  8. 指针 保存地址 初始指针 int * p
    & 取地址 取出变量a的地址
    * 解引用 找到对应地址中的内容
    32位操作系统 x86 所有指针类型均占用4个字节
    64位操作系统 x64 所有指针类型均占用8个字节
  9. 空指针 用于给指针变量进行初始化 不可以访问0~255是系统占用的,因此不可以访问
  10. 野指针 指向非法的内存空间 直接给指针一个未知地址
  11. const 修饰指针
    a. 常量指针
    指针的指向可以更改,但是指针指向的值不可以改
    int a = 10;
    const int * p = &a;
    b. 指针常量
    指针的指向不可以更改,指针指向的值可以改
    int a = 10;
    int * const p = &a;
    c. 同时修饰
    均不可以修改
    int a = 10;
    const int * const p = &a;
    记忆技巧 const和*的位置关系,修饰谁谁不可以修改
  12. 结构体 一些类型数据的集合的一个类型
struct 结构体名 {结构体成员列表};

struct Student{
    string name;
    int age;
    int score;
}

struct 创建变量可以省略,定义不可以省略

三种创建变量方式

1、struct Student s1;
s1.name = "zhangsan";
s1.age = 18;
s1.socre = 100;

2、struct Student s2 = {"lisi", 19, 80};

3、struct Student{
    string name;
    int age;
    int score;
}s3; 很少用
  1. 结构体数组
    将自定义的结构体放到数组中方便维护
定义
struct 结构体名 {结构体成员列表};
struct Student{
    string name;
    int age;
    int score;
};


创建结构体数组
struct Student stuarr[3] = {
    {"12",18,50},
    {"22",18,50},
    {"32",18,50},
};

22、结构体指针

定义
struct 结构体名 {结构体成员列表};
struct Student{
    string name;
    int age;
    int score;
};

struct Student stu1 = {"12", 18, 50};

& 取什么类型数据的地址,返回的就是什么类型
struct Student *p = &s;

通过结构体指针访问结构体中的属性,需要利用->
name = p->name;

23、结构体嵌套结构体
结构体中成员可以是另一个结构体

struct Student{
    string name;
    int age;
    int score;
};
struct Teacher{
    int id;
    string name;
    int score;
    struct Student stu;
};

teacher T1;
T1.id = 1
T1.name = "hh"
T1.stu.name = "qq"
T1.stu.age = 20
T1.stu.score = 18
  1. 结构体做函数参数
  • 值传递 .访问 形参改变,实参不变
  • 地址传递 ->访问 形参改变,实参改变
  1. 结构体中const使用场景
    结构体地址传递,节省内存空间
    形参之前加入const,防止误修改
  2. 内存的分区模型
    代码区 程序运行前
    存放函数体的二进制代码,存放CPU执行的机器指令,共享,只读

全局区 程序运行前
全局变量 静态变量 常量,程序结束后由操作系统释放
const修饰局部变量变为局部常量也不在全局区

栈区 程序运行后
编译器自动分配释放 存放函数的参数值、局部变量
不要返回局部变量的地址

堆区 程序运行后
程序员分配释放 ,若程序员不释放,程序结束由操作系统回收
new int(10) 创建堆区数据,返回的是这个数据的地址即相应的指针
delete p 释放堆区数据,再访问会报错
new * arr = new int[10] 创建数组堆区
delete[] arr 释放数组
26. 引用 给变量起别名
int a = 10
int &b = a
注意事项
-引用必须要初始化
-引用一旦初始化后,就不可以更改了
-赋值操作不是更改引用

引用做函数参数

void Swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}

int a = 10;
int b = 20;
Swap(a, b);
\\ 上面操作相当于int &a = a;给a起了个别名,函数中同样可以修改实参

引用做函数的返回值
-不要返回局部变量的引用 ,局部变量保存在栈区,函数结束会释放
-如果函数的返回值是引用,这个函数调用可以作为左值

引用的实质
本质:引用的本质在C++内部实现是一个指针常量

常量引用
作用:常量引用主要用来修饰形参,防止误操作

错误
int a = 10;
int &ref = 10;

正确
const int & ref = 10;
编译器替换为
int temp = 10;
const int & ref = temp;

主要应用
防止形参改变影响原始值
将形参变为 const int &val
  1. 函数提高
    函数的默认参数
    -如果函数从某个参数后为默认参数,之后的参数都必须为默认参数,和python一样
    -如果函数声明有默认参数。函数实现就不能有默认参数,函数和声明中只能有一个默认参数

函数的占位参数
目前占位参数无用,之后会用到
占位参数还可以为默认参数

void func (int a, int){
    cout << a <<endl;
}
func(10, 10);

void func (int a, int = 10){
    cout << a <<endl;
}
func(10);

函数重载
函数名可以相同,提高复用性
满足条件:
-同一个作用域下
-函数名称相同
-函数参数类型不同,或者个数不同或者顺序不同
注意事项
-函数的返回值不可以作为函数重载的条件
-引用作为重载的条件
是否加const可以作为重载条件

-函数重载碰到默认参数,会出现二义性,避免出现这种情况
如果只传一个参数,编译器不知道调用哪个,如果传入两个则没有这种问题

  1. 类和对象
    class 类名 {属性 行为}

访问权限
公共权限public 成员 类内可以访问,类外可以访问
保护权限protected 成员 类内可以访问,类外不可以访问 儿子可以访问父亲的保护内容
私有权限private 成员 类内可以访问,类外不可以访问 儿子不可以访问父亲的私有内容
29. struct和class的区别
struct默认权限是公共权限
class默认权限是私有权限
30. 成员属性设置为私有
-可以自己控制读写权限
-对于写可以检测数据的有效性
31. 对象的初始化和清理
构造函数和细够函数,自动由编译器调用,如果自己不写,编译器会提供,不过是空实现

构造函数的分类和调用
按照参数分类 无参构造(默认构造)和有参构造
按照类型分类 普通构造 拷贝构造 Preson(const Person &p)(将传入的人身上所有的属性,拷贝到我身上)

调用
括号法

显示法

隐式转换法

拷贝构造函数的调用时机
-使用一个已经创建完毕的对象来初始化一个对象
-值传递的方式给函数参数传值
-以值方式返回局部对象

构造函数的调用规则

深拷贝和浅拷贝
浅拷贝是简单的赋值复制
析构函数可以定义堆区数据释放,而浅拷贝带来的问题就是堆区内存重复释放
深拷贝,自己申请堆区存储数据

初始化列表

类对象作为类成员
当其他类对象作为本类成员时,先构造其它类,在构造本类
析构时正好相反,先析构本类,再析构其它类

静态成员
-静态成员变量 不属于某一个对象上,所有对象都共享一份数据
通过对象来访问 通过类名进行访问

也是拥有权限的,设置为私有则类外无法访问
a所有对象共享同一份数据,b编译阶段就分配内存,c类内声明,类外初始化操作

-静态成员函数
a所有对象共享同一个函数 b静态成员函数只能访问静态成员变量(因为无法区分普通变量属于哪个创建对象,因为这个函数是共享的)
也有访问权限
两种访问方式

  1. 对象模型和this指针
    空对象占用内存空间为1,为了区分空对象占内存的位置,每个空对象应该有一个独一无二的内存地址

成员变量和成员函数是分开存储的
计算对象占用内存大小时
非静态成员变量属于类的对象上,静态成员变量不属于类对象上,非静态成员函数也不属于类对象上,静态成员函数也不属于类对象上

this指针
this指针指向 被调用的成员函数 所属的对象
a 解决名称冲突 类内成员变量和构造函数的形参变量名称相同
b 返回对象本身 用*this (类似于python中的self??)
返回的值是一个对象则是新创建的一个对象,加上引用才是返回一个地址

空指针调用成员函数

const修饰成员函数 常函数
常函数内不可以修改成员属性

this指针的本质 是指针常量 指针的指向不可以修改
mutable 加入后可以修改

常对象 const修饰对象
常对象里面属性也不可以修改,除了加mutable修饰
常对象只能调用常函数
33. 友元
让一些特殊的类或函数可以访问私有属性
-全局函数做友元
在类中声明一下 friend 函数声明
-类做友元
在类中声明一下 friend 类
-成员函数做友元
在类中声明一下 friend 类::成员函数
34. 运算符重载
运算符重载也可以发生函数重载
-加号运算符重载
全局函数重载
成员函数重载
-左移运算符重载
-递增运算符重载
-赋值运算符重载
C++编译器至少给一个类添加4个函数
默认构造函数、默认析构函数、默认拷贝构造函数、operator+函数
-关系运算符重载
-函数调用运算符重载()
由于使用起来非常类似于函数调用,因此称为仿函数
类+()是匿名对象,这一行结束直接释放
35. 继承,减少重复代码
继承方式
公共继承, 保护继承,私有继承

父类中所有非静态成员属性都会被子类继承下去,私有属性被继承了,但是被编译器隐藏了

继承中的构造和析构顺序
先构造父类,后子类,析构相反

继承中同名成员处理
当子类中有和父类同名的成员函数时,会隐藏所有父类中的同名函数,访问需要添加作用域
直接调用是调用子类的
如果通过子类对象,访问父类的中的同名成员,需要加作用域

继承中同名静态成员处理方式
-通过对象访问
-通过类名访问

多继承语法
class 子类:父类1,父类2

菱形继承
利用虚继承解决菱形继承问题

  1. 多态
    -静态多态
    地址早绑定
    -动态多态
    地址晚绑定
    父类中函数变为虚函数
    满足条件 1、继承条件2、子类重写父类的虚函数
    使用 父类的指针或引用指向子类对象
    好处 1、组织结构清晰2、可读性强3、对于前期和后期扩展以及维护性高

  2. 纯虚函数和抽象类
    纯虚函数virtual void func() = 0
    包含纯虚函数的类为抽象类,抽象类无法实例化,子类必须重写纯虚函数

  3. 虚析构和纯虚析构
    利用虚析构解决父类指针释放子类对象时不干净的问题,如果子类中没有堆区数据,可以不写虚析构或纯虚析构
    纯虚析构有声明也要有实现,有了纯虚析构之后,也为抽象类

  4. 文件操作
    -文本文件
    写文件
    1、#include 2、创建对象流 ofstream ofs; 3、打开文件ofs.open(""文件路径“,打开方式) 4、写数据 ofs<<"写入的数据" 5、关闭文件 ofs.close();
    读文件
    1、#include 2、创建对象流 ifstream ifs; 3、打开文件ifs.open(""文件路径“,打开方式) 4、读数据 四种方式 5、关闭文件 ifs.close();
    -二进制文件

  5. 模板
    模板只是一个框架,不能单独使用,并不是万能的

函数模板

template<typename T>
函数声明或定义
mySwap(T &a, T &b){
T temp = a
a=b;
b=temp;
}

int a = 10;
int b = 20;

两种使用方式
1、自动类型推导
mySwap(a,b);
2、显示指定类型
mySwap<int>(a, b);

注意事项:
自动类型推导,必须推导出一致的数据类型T,才可以使用
模板必须要确定出T的数据类型才可以使用

普通函数和函数模板的区别
-普通函数调用可以发生隐式类型转换
-函数模板 自动推导不会发生
-函数模板 显示指定类型,可以发生

普通函数和函数模板调用规则
-优先调用普通函数
-可以通过空模板参数列表 强制调用 函数模板
-函数模板可以发生函数重载
-如果函数可以产生更好的匹配,优先调用函数模板

模板的局限性

类模板和函数模板之间的区别
-只有显示指定类型的使用方式
-类模板参数列表可以有默认参数

类模板中成员函数只有在调用时才会创建出来

通过类模板创建的对象,有三种方式向函数中 进行传参
-指定传入类型
-参数模板话
-整个类模板化

类模板与继承
指定父类模板中的参数列表

类模板分文件编写
-直接包含文件本身
-.h和.cpp写在一起,.hpp文件后缀

类模板与友元函数
-全局函数类内实现
正常实现
-全局函数类外实现
需要让编译器提前知道全局函数的存在

  1. STL
    面向对象三个特性
    封装 继承 多态
posted @ 2024-05-09 21:51  xjx111  阅读(1)  评论(0编辑  收藏  举报