C++
Jackie

黑马|C++

字符

字符型

char ch='a'

字符串

C风格:

char str[]="hello"

C++风格:

#include <string>
string str="hello"

※分文件编写

  1. 创建后缀名为.h的头文件
  2. 创建后缀名为.cpp的源文件
  3. 头文件中写函数的声明
  4. 源文件中写函数的定义
//swap.h头文件
#include<iostream>
using namespace std;

//函数声明
void swap(int a , int b);
//swap.cpp文件
#include"swap.h"
void swap(int a , int b){
...
}
//main.cpp文件
#include"swap.h"
int main(){
...
}

指针

在32位操作系统下占用4个字节,64位下占用8个字节(和数据类型无关!

空指针

指针变量指向内存中编号为0的空间

  • 用途:初始化指针变量
  • 注意:空指针指向的内存不可访问!
int * p = NULL;

内存编号为0~255为系统占用内存,不允许用户访问

野指针

指针变量指向非法的内存空间

int * p = (int *)0×1100;

const修饰指针

三种情况:

int a=10;
int b=10;
  1. 修饰指针—常量指针

特点:指针指向可修改,但指针指向的值不可修改

const int *p=&a;
*p=20;//×
*p=&b;//√(指向可以改)
  1. 修饰常量—指针常量(常指针)

特点:指针指向不可修改,指向的值可修改

int * const p=&a;
*p=20;//√
*p=&b;//×
  1. 既修饰指针,又修饰常量

特点:指针指向和指向的值都不可修改

const int * const p=&a;
*p=20;//×
*p=&b;//×

技巧:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量

结构体

用户自定义的数据类型,允许存储不同的数据类型

定义&使用

语法:struct 结构体名 { 结构体成员列表 };

通过结构体创建变量的三种方式:

  • struct 结构体名 变量名
  • struct 结构体名 变量名={成员1值,成员2值…}
  • 定义结构体时顺便创建变量

定义结构体变量时关键字struct不可省略

创建结构体变量时关键字struct可省略

struct student { ... }

int main(){
(struct) student stu1={ ... };
}

结构体数组

将自定义的结构体放到数组中,方便维护

语法:struct 结构体名 数组名[元素个数]={ {},{},… {}}

struct student arr[3]={
{"张三"18,80},
{ ... },
{ ... }
}

给数组中的元素赋值

arr[2].name="赵六";

结构体指针

通过指针访问结构体中的成员

  • 利用操作符->可以通过结构体指针访问结构体属性
struct student s={ };
struct *p=&s;
cout<<"姓名:"<<p->name<<endl;

内存分区模型

  • C++中在程序运行前分为全局区和代码区
  • 代码区的特点是共享只读
  • 全局区中存放全局变量静态变量常量
  • 常量区中存放const修饰的全局常量字符串常量

new

在堆区创建整形数据

new返回的是该数据类型的指针

引用

语法:数据类型 &别名 = 原名

注意事项:

  • 引用必须初始化,且初始化后不可改变

引用做函数参数

作用:函数传参时可利用引用的技术让形参修饰实参

优点:简化指针修改实参

//三种交换值方法:值传递、地址传递、引用传递
void swap(int &a,int &b){
int temp=a;
a=b;
b=temp;
}
int main(){
int a=10;
int b=20;
swap(a,b);
cout<<"a:"<<a<<"b:"<<b<<endl;
return 0;
}//a=20,b=10

通过引用参数产生的效果同地址传递是一样的。引用语法更清楚简单。

*引用做函数返回值

引用可作为函数的返回值存在

不要返回局部变量的引用

函数的调用可作为左值

int& test(){
static int a=10;
return a;
}
int main(){
int &ref=test();
cout<<"ref:"<<ref<<endl;
test()=100
cout<<"赋值后ref:"<<ref<<endl;
}//ref=10
//ref=100

如果函数的返回值是引用,这个函数调用可作为左值

函数

函数默认参数

C++中函数才形参列表中形参是可以有默认值的

语法:返回值类型 函数名(参数=默认值){}

注意事项

  1. 若某个位置已有默认参数,那么从该位置往后,从左到右都必须有默认值

  2. 函数声明和实现只能有一个默认参数

函数占位参数

C++中函数形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置

语法:返回值类型 函数名(数据类型){}

//函数占位参数,占位参数也可有默认参数
void fun(int a,int){}
int main(){
fun(10,10);//占位参数必须填补
}

※函数重载

满足条件:

  • 同一作用域下
  • 函数名称相同
  • 函数参数类型不同 或者个数不同 或者顺序不同

注意事项

  • 函数的返回值不可以作为函数重载的条件
void fun(int a,int b){}
int fun(int a,int b){}
//×,两者仅返回值(int/void)不同
  • 引用作为重载条件
void fun(int &a){}
void fun(const int &a){}
int main(){
int a=10;
fun(a);//调用无const版本
fun(10);//调用有const
}
  • 函数重载避免默认参数

类和对象

权限 访问权限
公共权限public 类内可以访问 类外可以访问
保护权限protected 类内可以访问 类外不可访问 子类可以访问父类中的保护内容
私有权限private 类内可以访问 类外不可访问 子类不可访问父类中的保护内容

构造函数&析构函数

构造函数

语法:类名(){}

  1. 无返回值 也不写void
  2. 函数名称与类名相同
  3. 可以有参数,即可以发生重载
  4. 程序调用对象时自动调用构造,无需手动调用,且只会调用一次

析构函数

语法:~类名(){}

  1. 无返回值 也不写void
  2. 不可以有参数,因此不可发生重载

构造函数的分类及调用

分类

两种分类方式:

  • 按参数分:有参构造 无参构造(默认构造)
  • 按类型分:普通构造 拷贝构造
//拷贝构造函数
Person(const Person &p){}

调用

三种调用方式:

  • 括号法
  • 显示法
  • 隐式转换法
void test(){
//括号法
Person p1;//默认构造函数调用[不要加()!编译器会认为是一个函数的声明]
Person p2(10);//有参构造函数
Person p3(p2);
//显示法
Person p1;
Person p2=Person(10);//有参构造
Person p2=Person(p2);//拷贝构造
//隐式转换法
Person p4=10;//相当于Person p4=Person(10);
Person p4=p4;//拷贝构造
}

Person(10);//匿名对象,特点:当前执行结束后,系统会立即回收掉匿名对象

注意:不要利用拷贝构造函数,初始化匿名对象,编译器会认为Person(p3) === Person p3//对象的声明

拷贝构造函数调用时机

  • 使用一个已经创建完毕的对象来初始化一个对象
  • 值传递的方式给函数参数传值
  • 以值的方式返回局部对象

构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝析构函数,对属性进行值拷贝

调用规则:

  • 若用户定义有参构造函数,C++不再提供默认无参构造,但会提供默认拷贝构造
  • 若用户定义拷贝构造函数,C++不再提供其他构造函数

※深拷贝与浅拷贝

面试经典问题,常见的一个坑

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作

浅拷贝带来的问题:堆区的内存重复释放(利用深拷贝解决

总结:若属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

初始化列表

Person(int a,int b,int c):a(a),b(b),c(c){ ... }
int main(){Person p;}

类对象作为类成员

当其他类对象作为本类成员(对象成员),先调用对象成员的构造,再调用本类的构造,析构的顺序与构造相反

静态成员

在成员变量和成员函数前加上关键字static

静态成员变量

  • 所有对象共享同一份数据
  • 在编译阶段分配内存
  • 类内声明,类外初始化
class person{
public:
static int a;
};
int person::a=1;

静态成员变量不属于某个对象上,所有对象都共享同一份数据

因此静态成员变量有两种访问方式

  1. 通过对象进行访问
person p;
cout<<p.a<<endl;
  1. 通过类名进行访问
cout<<person::a<<endl;

有访问权限,私有权限访问不到

静态成员函数

  • 所有对象共享同一个函数
  • 静态成员函数只能访问静态成员变量

同上有两种访问方式,且有访问权限

空对象占用内存空间为:1

C++编译器会给每个空对象分配一个字节空间,是为了区分空对象占内存的位置

this指针

本质:指针常量

指向被调用的成员函数所属的对象

是隐含每一个非静态成员函数内的一种指针

用途:

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this

const修饰成员函数

常函数

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改

常对象

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数

排序算法

冒泡排序

  1. 比较相邻的元素,若前一个比后一个大,交换他们两个
  2. 对每对相邻元素做同样工作,执行完毕后找出第一个最大值
  3. 重复以上步骤,每次比较次数-1,直到无需比较
  • 外层循环:排序总轮数=元素个数-1
  • 内层循环:每轮对比数=元素个数-排序轮数-1

杂项

  1. 数组个数计算方法:
sizeof(arr)/sizeof(arr[0])-1
  1. 随机数生成
#include<ctime>//添加随机数种子(利用当前系统时间生成随机数,防止每次随机数都一样)
srand((unsighed int)time(NULL));
int num=rand()%100//生成0~99随机数

visual studio中Ctrl+D快速复制当前一行

值传递时,函数形参发生改变,并不会影响实参

 评论
评论插件加载失败
正在加载评论插件