您的位置:首页 > 财经 > 产业 > C++知识点

C++知识点

2024/11/18 14:26:35 来源:https://blog.csdn.net/weixin_44965579/article/details/141888837  浏览:    关键词:C++知识点

1.CV限定符

const

        用于声明常量

声明常量变量:

const int MAX_SIZE = 100;

 常量函数参数

//防止函数修改n,通常与引用一起使用
void fun(const int& n){}

 常量成员函数

//保证函数不会修改成员变量
void classname::show(xxx) const;//定义
void show(xxx) const;//声明
1.const int* ptr = &age;
ptr是一个const的(int*)类型,不可以用*ptr去修改age,但是可以直接修改age。
const变量地址可以赋给const指针,不可赋给常规指针2.int* const ptr = &age;
ptr是const *int类型的指针,即ptr是const,但是指向的内容不是const。
ptr只能指向age,但是可以使用*ptr改变age的值3.int const *ptr = &age;

volatile

不进行编译优化,会从内存中取数据,而不是寄存器
某些情况,编译器会自动优化,修改变量存取过程。修改后,当一些变量存在cpu寄存器中时,编译器会让cpu直接从寄存器读取,而不是内存中。如果有一个线程对内存中该变量进行了修改,则cpu从寄存器读取而不是内存,就出问题。
tips:mutable(可变的)

2.函数指针和指针函数

函数指针

函数地址:就是函数名

如何获取函数指针:

double pam(int)//函数
double (*pf)(int);//函数指针

使用:(*pf) 与 pam()相等 

区分:

double (*pf)(int);//返回double的函数指针
double *pf(int);//返回double*的函数

指针函数

返回值时指针的函数

3.类

定义

class MyClass:public BaseClass{    //public继承private:int myVar;int* data = new int;public:void myFun()//构造函数,特征:无返回值;函数名=类名;可以定义多个不同参数(多态)MyClass(int value, int data){int myVar = value;*data = data}//拷贝构造函数,特征:无返回值;函数名=类名;参数为MyClass &other;MyClass(const MyClass& other){//深拷贝,对每个成员变量挨个拷贝myVar = other.var;*data = *(other.data);}//析构函数,特征:无返回值;函数名"~类名"~MyClass(){//释放资源delete data;}//运算符重载,特征:返回值MyClass&;类名"operate重载的符号";MyClass& operator=(const MyClass& other){if(this != &other){myVar = other.myVar;delete data;data = new int;*data = *(other.data)}return *this;}
};

实例化

MyClass obj;
MyClass* obj = new MyClass();//new方式

this和*this

this //对象地址
*this //对象本身

封装

3中封装方式的区别:

继承

3个继承方式的区别:
 

多态

允许同样的函数接口在不同的对象上表现出不同行为,依靠虚函数动态绑定实现。

重写

重写父类虚函数。

虚函数

使用virture关键字。派生类可以覆盖虚函数。通过使用指向基类对象的指针或者引用调用虚函数时,程序将根据运行实际对象类型来确定调用函数。

编译器对虚函数使用动态联编
动态联编:
静态联编:
虚函数列表:存放虚函数地址,当虚函数被重写,放入新的地址。tips:构造函数不能为虚析构函数应该为虚友元不能为虚

纯虚函数

即接口,只声明不实现,让子类实现
virtual int fun()=0;//声明,特征多一个"=0"

重载

在同一个作用域内,可以定义多个同名不同参数列表的函数。 

1.函数名相同
2.参数列表必须不同(参数类型、数量、顺序)
3.返回类型可以相同可以不同

 参数列表

1.参数类别即函数特征标(不包含返回值,所以返回类型可以不同)
2.参数加了引用和不加,特征标相同

 运算符重载

1.自定义数学运算
2.容器类和迭代器:使用运算符重载提供方便操作,如.运算
3.输入输出流:例如cout和cin就对"<<"进行重载以处理不同类型的输入
4.比较和排序:重载"<","=="等
5.实现迭代器功能:例如"++","--"
重载的限制
重载的限制:1.重载后的运算至少有一个操作数时用户定义的类型2.使用运算符时不得违反运算符原来的句法规则3.不能创建新运算符4.不能重载sizeof、"."、".*"、"::"、"?:"等运算符5.以下运算符只能通过成员函数重载:"="、"()"、"[]"、"->"
运算符重载和友元

两种运算符重载

1.成员函数Time Time::operator*(double m) const{//用于实现time*m,其实是调用time*(m)}2.非成员函数(使用友元,调用Time的成员变量)Time Time::operator*(double m, const Time& t){//实现m*time。调用m*(m, time),但是m不是成员函数,没有权限调用time,所以就需要友元}

析构函数

1.资源释放
2.清理操作
3.继承关系下的调用顺序:派生类的析构函数会自动调用基类的虚构函数,逐层清理父类资源
4.析构顺序:1.成员变量按照声明的逆序进行销毁2.派生类先于基类进行销毁
tips:1.只能有一个2.可以自动生成3.小心处理指针和资源释放

深拷贝与浅拷贝

拷贝构造函数

定义:注意事项:1.系统会自动生成默认拷贝构造函数和赋值运算符重载,但是当涉及动态内存分配需要自己写。

程序在什么时候执行的是浅拷贝、深拷贝、=赋值运算?

1.值传递参数、以值返回对象、使用初始化列表进行对象初始化时都会调用拷贝构造函数
2.当两个同类型对象使用"="时,调用赋值运算符重载函数

友元 

1.友元在类中声明,但不是成员函数,不需要classname::
2.不是成员函数,但是可以访问成员
3.只在声明处加friend关键字,定义处不加
友元函数

在一个类内部声明并定义的独立函数,但不属于该类的成员。通过friend关键字声明。可以直接访问该类的私有和保护成员。

使用场景:1.两个类需要共享私有数据,将一个类的成员函数声明为另一个类的友元函数2.重载二元运算符,通常将运算符重载函数声明为友元
友元类

友元类指在一个类中声明另一个类为其友元

使用场景:1.类共享数据2.代理模式、迭代器模式等中会使用到
友元成员函数

列表初始化

比普通初始化更严格,不允许缩窄

其他

struct和class区别:1.struct默认共有和公有继承,不自动生成构造函数2.class默认私有和私有继承,自动生成构造函数

4.内存泄漏

1.谨慎使用new和delete
2.使用智能指针
3.定期检查和测试
4.使用容器类和标准库
5.遵从编码规范
6.使用内存分析工具

5.智能指针

share_ptr:共享指针,使用引用计数器追踪有多少个指针指向同一个资源,只有当最后一个指针销毁时,才会释放资源。存在循环引用问题。
unique_ptr:独占指针确保只有一个指针可以访问该资源,会自动释放
weak_ptr:弱指针,没有计数器,解决循环引用问题。

6.堆和栈

1.分配方式:
2.空间大小限制
3.分配速度:
4.生命周期:栈自动;堆手动,处理不好会内存泄漏
5.数据访问方式:栈访问更快,内存地址是连续的;堆由内存管理分配,可能是不连续的
6.使用场景:栈一般是自动存储,保持局部变量、函数调用过程中的参数传递;堆动态(手动)创建,需要手动释放tips:自动存储静态存储动态存储

7.static

三种静态变量的作用域 

int global = 1000;    //所有文件,但需要extern
static int one = 1;    //本文件内void fun(){static int two = 2;
}    //

静态成员变量

1.所有类公用一个静态变量
2.静态成员变量需要在类外单独初始化

静态成员函数

1.只与类关联,不需要实例化就可调用,并可以直接访问静态成员函数

8.new和delete 

需要手动释放,不要多次delete

在函数调用中的分配与释放需要注意的情况:

分配与释放

//分配
int* ptr = new int;
double* arr = new double[10];//释放
delete ptr;
delete[] arr;
ptr = nullptr;    //置空防止野指针tips:C++中的arr:长度固定vector:长度可扩展

new和malloc 

1.成功时new返回具体指针,malloc返回*void
2.失败时new返回异常,malloc返回null
3.是否需要指定内存大小
4.new/delete可重载,malloc/free是函数
5.new/delete会调用构造析构函数
6.delete时,new自动将指针指向nullptr;malloc没有
7.new和delete是运算符

9.引用与指针

引用定义

1.引用 = 别名
2.必须初始化,不能为空,一经初始化后不可改变
3.不支持地址运算
4.又叫左值引用(还有一个右值引用,用于移动语义)

将引用参数声明为const

1.避免无意中修改数据
2.使函数可以处理const和非const实参,否则只能接受非const
3.使函数能够正确生成并使用临时变量

当返回值为引用时

1.避免返回函数内定义的临时变量
2.应该返回参数传进来的引用,并且形参使const时,返回值也应该是const
3.或者返回该函数new出来的,但是必须记得在函数外delete,否则内存泄漏

10.模板

C++特性之一:泛型编程

定义

//模板类
template <typename T>
class Container{
private:T data;public:Container(T value):data(value){}    //新特性,列表初始化void print(){std::cout << "Data:" << data << std::endl;}
};//模板函数
template <typename T>
T maximum(T a, T b){return (a > b ) ? a : b;
}

11.异常处理

1.
2.

12.STL常用容器

1.vector
2.list
3.deque
4.map
5.set
6.unorder_map
7.unorder_settips:stack和queue是容器适配器,可指明由其他容器作为底层实现

13.迭代器

用于遍历容器的抽象概念,可以理解为指针。

声明

std::vector<int>::iterator it;

其他迭代器

begin()    //第一个元素
end()    //超尾,指向最后一个元素的下一个

使用auto it 简化操作

14.命名空间

1.避免命名冲突
2.组织代码
3.全局声明隔离

使用

1.using namespace std放在函数定义之前,让文件中所有函数都能用
2.using namespace std放在函数内
3.在函数内使用using std::cout
4.直接使用std::cout

15.预处理器

在编译前对代码进行一系列文本替换和指令处理,通常以"#"开通,不是正真的C++代码。

文件包含

#include <iostream>
#include "../../xxx"C++与C的include的区别:1.新式C++没有扩展名2.C中#include<math.h>C++中#inclde<cmath>

宏定义

#define MAX(a, b) ((a) > (b)> ? (a) :(b))为什么要加这么多括号?因为宏定义只是进行简单的字符替换,非常容易出问题宏定义函数和内联函数的区别:
1.
2.

条件编译

1.#ifdef
2.#ifndef
3.#if

 16.文件操作

文件写入

文件读取

追加写入

17.指针与数组

int arr[] = {1, 2, 3, 4};
int* ptr = arr;1.sizeof(arr)是数组长度;sizeof(ptr)是地址长度
2.arr是常量,ptr可修改
3.arr是第一个元素地址
4.++运算每次加一个类型的长度,即指向下一个元素地址
5.当arr作为参数传入函数时,sizeof(arr)是地址长度即4,所以当传数组名arr时一般还会传个数组长度n

18.排序算法

1.冒泡
2.选择
3.插入
4.快排
5.归并
6.堆排

19.设计模式

单例模式

观察者模式

工厂模式

适配器模式

策略模式

装饰器模式

模板方式模式

20.线程

创建

#include<thread>std::thread myThrad(theadFun);    //函数名作为参数创建线程
myThread.join()    //等待线程执行完毕

21.线程同步

互斥锁

22.Lambda表达式

匿名函数

定义

[capture list] (parameters) -> return_type{//函数体
}capture list:捕获列表,用于指定lamda中所使用的外部变量

 22.内联函数

将内联函数插入调用点提高程序运行效率,减少上下文切换的开销。

1.声明和定义前加inline
2.内联不能递归
3.虚拟成员函数无法内联

内联与宏定义区别 

1.内联函数是在编译过程中,编译器会进行检查,如果过于复杂会放弃内联,当做普通函数执行
2.宏定义是编译前的预处理,只进行简单字符替换,不进行检查

23.动态绑定

即运行时多态,在程序运行时根据实际对象类型决定调用哪个方法或函数。

24.移动语义 

25.类型转换

隐式类型转换

int num = 3.14;

explicit关键字

explicit关键字用于关闭隐式转换,只允许显示类型转换,防止不必要的问题 

c++98中explicit关键字不能用于类型转换
c++11支持

显示转换 

C风格强转

int num = (int)3.14;tips:int强转是四舍五入,不是去掉小数部分

函数风格强转

int num = int(3.14);

dynamic_cast转换 

//执行类层次间的安全向下转型或基类到派生类的向上转型
dynamic_cast<type>(expression);    //运行时进行类型检查

自定义类型转换函数

类中可以定义转换函数
1.转换函数必须是类的方法
2.不能指定返回类型
3.不能有参数class MyType{
private:int value;
public:MyType(int v = 0) : value(v){}operator int() const{return value;}
};int main(){MyType obj(42);int num = obj;    //隐式调用int num1 = static_cast<int>(obj);    //显示调用return 0;
}

26.尾递归

27.浮点运算精度问题

阈值法

double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 1e-6;if(std::abs(a - b) < epsilon){//在可接受范围内
}

比较法 

double a = 0.1 + 0.2;
double b = 0.3;
double relative_error = std::abs((a - b) / b);if(relative_error < 0.01){//误差在可接受范围内
}

28.数组

1.只有在定义时才能初始化int cards[4] = {1, 2, 3, 4};
2.如果初始化给的数量小于长度,其他默认为0int cards[10] = {0};
3.不指定长度int cards[] = {1, 2, 3, 4};C++特性
1.可以省略"="int cards[4] {1, 2, 3, 4};
2.可以{}无任何值表示默认为0int cards[10] = {};
3.禁止缩窄操作

29.字符串

1.sizeof():字节长度
2.strlen():可见字符长度

C风格

1."\0"结尾char dog[3] = {'d', 'o', 'g'};    //可修改,长度为4,默认\0char dog[] = "dog";    //常量,不可修改,长度为4

string

29.内存管理方式

1.自动存储:自动变量存于栈
2.静态存储:定义函数外的;static的;整个程序执行期间都存在
3.动态存储:

30.野指针和悬浮引用

野指针:指向已经释放或内存无效的指针
1.delete后未置空
2.返回局部变量的指针
3.函数参数指针被释放悬浮引用:指向已被销毁对象的引用

31.内存对齐

数据在内存中存储起始地址是某个值的倍数
提高cpu访问效率,减少内存访问次数tips:1.结构体和共同体的内存对齐,共用体长度是最大类型长度

32.char

1.默认情况下即不是无符号也不是有符号
2.可以显示指定有无符号unsigned char c;signed char c;

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com