C++常用知识大总结


B站c++教程

内存四区

代码区:存放函数体二进制代码,有操作系统管理
全局区:存放全局变量,静态变量(static修饰变量)和常量(string类型数据,const修饰的内容)
栈区:由编译器自动分配和释放,存放函数参数值,局部变量。(注意:不要再函数里返回函数变量地址,会被编译器自动释放然后丢失)
堆区:由程序员自动分配和释放。不释放就由系统回收。

输出变量地址,可以获得结论。

new

new/malloc 区别

使用new申请的内存由free store自由存储区分配给程序员,malloc是堆区,可以由程序员自行使用。相比于malloc,new更安全,无需指定内存大小,允许重载,可以初始化数组对象,返回完整类型指针,默认抛出异常。

int *a=new int(10);//为a开辟1个int,4字节空间
					//如果这个作为函数成员变量,函数结束后不会自动释放;
delete a;//释放a内存

int *arr=new int[10];//为arr分配大小为10个int的数组

delete [] arr;//释放arr数组

new operator和operator new区别

new就是new operator. operator new调用了malloc分配内存。
当使用new关键字时,编译器:
1.用operator new()分配内存
2.调用对应数据类型(string,int等等)构造函数
3.返回对应类型指针

placement new

保持一块内存反复构造,析构。可以省去反复分配内存。

引用

引用:给变量起别名,外号。

int a=10;
int &b=a;//使用b这个称号也能操作数值10
		//注意引用必须初始化,int &b写法是错误的
		//引用初始化后不能改变
		//引用 的外号 可以操作变量内存
b=20;
cout<<b<<endl;//结果是20
  • 引用 做函数参数
    用swap(a,b)作为例子,地址传递和引用的方法一样,但是写法更简洁
void swap1(int *a,int *b){
	int tmp=*a;//tmp 为一个地址
	*a=*b;
	*b=temp;
}

void swap2(int &a,int &b){//引用写法写入实参
	int c=a;
	a=b;
	b=c;
}

  • 引用作函数返回值

// !!不能返回局部变量引用
int& test(){
	static int a=10;//如果不添加static,返回引用就会失败,因为栈区内存被编译器释放
	return a;
}

int main(){
	int &ref=test();//ref=a=10
	test()=1000;//引用使得函数可以变成左值被赋值,ref=a=1000
}






  • 引用和指针的区别。

      - 引用有指针的一部分功能,可以看作常量指针,int &tmp=a;与int const * tmp =a基本一致。
      - 再之后的调用tmp=20就相当于 *tmp=20一样。tmp指向的这个地址是不可修改的常量
    

static const

  • 关键字 static 有什么作用?
    1.隐藏,当我们同时编译多个文件时, 所有未加static前缀的全局变量和函数都全局可用,用static
    定义的不同文件的同名函数和变量不用担心命名冲突。
    2.使变量内容持久,程序刚开始就会把静态变量初始化,默认的初始化值为0,并且不做修改,两种变量存储在静态存储区:全局变量和static变量。

静态成员函数 static func().静态成员函数 只能访问静态变量


  • 关键字 const 有什么作用?(constant缩写:不变的)
    const 修饰的内容不可改变。const修饰的函数变量参数返回值受到强制保护。
    例如:const int N=1e5;

在这里插入图片描述


类与对象

封装

类的关键字和方法

public 内容都可以访问

protected 需要访问权限,子类可以访问

private	需要访问权限,子类不可以访问,像银行卡密码一样

struct里面默认public,class里面默认private

C++创建class会默认创建三个函数,构造(用于初始化对象),析构(释放对象后运行),拷贝函数(复制对象)。

#include<iostream>

using namespace std;


class Person {
	//不宣称类型就会默认private 
	public:
		string person_name;
		int age=18;
		
		Person(string name) {//构造 
			person_name=name;
		}
		~Person() {//析构 
			cout<<"对象被销毁了"<<endl; 
		}
		Person(const Person &p){//拷贝 
			person_name= p.person_name;
			age=p.age+1;
		}
		
		
}; 

int main(){
	
	//初始化列表也可以构造对象

	Person jack=Person("jack111");
	cout<< jack.person_name<<endl;
	cout<< jack.age<<endl;
	Person jim=Person(jack);
	cout<<  jim.age <<endl;
	system("pause");//这句结束才执行析构函数 
	
}

A类为B类属性时,先构造B,再构造A。释放是先析构A,再析构B;

浅拷贝 深拷贝

默认的拷贝函数只是浅拷贝,浅拷贝会复制地址,地址是同一个地方。浅拷贝存在一个问题就是:会导致堆区的内存被重复释放导致异常。(图中m_height是new申请的内存)
在这里插入图片描述

因此实现深拷贝需要再分配一份行的空间(地址),将原数据复制。

public:
	Person (const Person &p){
		m_height=new int(*p.m_height);
		//p.m_height是一个地址,*是解析地址,读取地址里的数据
	}


继承

写法:
在这里插入图片描述

三种继承方式的差异

在这里插入图片描述
且父类中所有非静态的成员都会继承,private属性不可访问,但任然会继承

  • 子类父类的顺序和使用成员类属性一样。
    在这里插入图片描述
  • 访问父子同名成员名/函数,默认子类,访问加父类作用域就行(这里被称为隐藏)

在这里插入图片描述

  • 多继承

在这里插入图片描述

多态

多态分为两类:
静态多态:函数/运算符重载,复用函数名
动态多态:通过派生类和虚函数实现运行时多态。

区别:静态多态地址早绑定会在编译时就确定函数地址,动态则是晚+运行时确定。

  • 下面是展示区别例子:
    地址早绑定会导致只执行父类的方法
    在这里插入图片描述
    在父类 方法前加上关键字virtual使得函数编程虚函数就可以实现地址晚绑定。
#include<iostream>

using namespace std;


class Animal {
	public:
		virtual void speak(){//不加virtual将会是另一种结果 
			cout<<"动物在说话"<<endl; 
		}
}; 


class Cat : public Animal{
	public:
		void speak(){
			cout<<"猫猫在说话"<<endl; 
		}
}; 


void doSpeak(Animal &animal){
	animal.speak();
}


void test(){
	Cat cat;
	doSpeak(cat);
}


int main(){
	test();
}

虚函数内存分析:
在这里插入图片描述

纯虚函数抽象类
在这里插入图片描述


重载,隐藏,重写(覆盖)

  • 重载,隐藏,重写(覆盖)三者区别?

  1. 重载:是指同一访问区内被声明的几个具有不同参数列的同名函数,根据参数列表决定调用。
    返回值类型不同不能作为重载标识
void test1(int a){
	cout<<"11111";
}
//const int a 可以作为重载条件


void test1(){
//这就是重载test1,两个函数根据参数不同可以一起使用,但返回值类型不同不能作为重载标识			
	cout<<"00000";
}


struct node{
	int id,pos,d;
	bool operator <(const node&x)const {//运算符重载
		return pos<x.pos;
	}
}
//这里就是程序对 <  功能的重载,< 传入参数会判断是node结构体还是具体数值
//使用用不同的比较标准来开始比较
  1. 隐藏:是指派生类的函数屏蔽了与其同名的基类函数。只要同名就会被隐藏。比如static修饰的同名函数会被隐藏掉。
  2. 重写(覆盖):是指派生类中存在重新定义的函数。
    与其函数名,参数列表,返回值类型都必须与原来重写的函数一致,只有函数体不同
    派生类只会调用重写的函数,而不会调用原函数(被重写函数)
    (这个和java子类重写父类方法有点相似)

运算符重载

写法: 返回值类型 operate 运算符 (返回值类型 & 参数名){}
调用: p.operate+(),也可以按算符原先的写法写。

通过成员函数重载就传入一个参数,全局函数就传入两个。

重载+号

在这里插入图片描述

重载<< 运算

用全局函数来重载<<实现结构体所有属性的输出。
在这里插入图片描述

没写完继续补

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值