目录
一
1始
1)编程序:
2)注释
3)变量
4)常量
5)关键字
6)标识符命名规则
2数据类型
1)
2)整型
3)sizeof关键字
4)实型(浮点型)
5)字符型
6)转义字符
7)字符串型
8)布尔类型bool
9)数据输入
3运算符
1)作用:运算
4程序流程结构
1)选择结构(if 、三目、switch)
2)循环结构(while、do...while、for)
3)跳转语句(break、continue、goto)
5数组
6函数
7指针
8 结构体
其他
二
1始
1)c++程序执行时,将内存大方向分为4个区域
2new关键字
3引用
4函数+
5类、对象
5.1)封装
5.2)对象的初始化和清理
5.3)c++对象模型、this指针
5.4)友元friend
5.5)运算符重载operator
5.6)继承
5.7)多态
6文件操作
6.1)
6.2)文本文件:
6.3)二进制文件
#define 宏常量 | #define 常量名 常量值 |
const修饰的变量 | const 数据类型 常量名 = 常量值 |
数据类型 | 占用字节 |
short短整型 | 2 |
int | 4 |
long | 4、8 |
long long | 8 |
数据类型 | 占用空间 | 有效数字范围 |
float | 4 | 7 |
double | 8 | 15-16 |
ti:float f1=3.14f
c | char 变量名[] ="字符串值" |
c++ | string 变量名 = "字符串值" |
运算符类型 | 作用 | 符号 |
算术运算符 | 四则运算 | + - * / % ++ -- |
赋值运算符 | 表达式赋值给变量 | = += -= *= /= %= |
比较运算符 | 比较返回真假 | == != < > <= >= |
逻辑运算符 | 根据表达式值返回真值、假值 | ! && || |
1.1if
单行格式 |
if(条件){条件满足执行的语句}; |
多行格式 |
if(条件){条件满足执行的语句}else{条件不满足执行的语句}; |
多条件格式 |
if(){}else if(){}...else{}; |
1.2三目运算符
1.3switch语句
2.1while
2.2do...while
2.3for
2.4嵌套
3.1break
switch中 | ,终止case并跳出switch |
循环 | 跳出当前循环循环语句 |
嵌套 | 跳当前循环 |
3.2continue
3.3goto
1)
2)一维数组
数据类型 数组名[数组长度]; |
数据类型 数组名[数组长度] = {值}; |
数据类型 数组名 [] = {值}; |
3)二维数组
数组类型 数组名[行号][列号]; |
数组类型 数组名[行号][列号] = {{值},{值}}; |
数组类型 数组名[行号][列号] = {值}; |
数组类型 数组名[ ][列号] = {值}; |
1)
2)定义
3)调用
4)值传递
5)函数的常见样式
6)函数声明
7)函数分文件编写
1)
2)定义与使用
//定义
int a = 10;
int * p ;
p = &a;
//使用
//解引用
cout<<"*p = "<<*p<
3)所占空间
4)空指针或野指针
5)const修饰指针
修饰指针--常量指针 | const int * p1=&a; | 指针指向可以变,指向的值不可变 |
修饰常量--指针常量 | int * const p2=&a; | 指针指向不可变,指向的值可变 |
都修饰 | const int* const p3=&a; | 都不能变 |
6)指针与数组
7)指针与函数
8)指针、数组、函数结合
1)
2 )定义与使用
struct 结构体名 变量名 |
struct 结构体名 变量名 = {成员}; |
定义结构体时顺便创建 |
void text() {
struct Student {
string name;
int age;
int score;
}stu2;//创建方法2
stu2.name = "李四";
struct Student stu1;//创建方法1
stu1.age = 18;
stu1.score = 99;
stu1.name = "张三";
cout << stu1.name<<"\t" << stu1.age << "岁\t" << "语文成绩:"<
3)结构体数组
4)结构体指针
5)结构体嵌套结构体
6)结构体做函数参数
7)结构体中const的使用
对面向对象的进一步学习
代码区 |
存放函数体的二进制代码,由操作系统进行管理 | 共享,只读。程序运行前 |
全局区 | 存放全局变量,静态变量,常量 | 操作系统释放。程序运行前 |
栈区 | 编译器自动分配释放,存放函数参数、局部变量等 | 不要返回局部变量地址。程序运行后 |
堆区 | 程序员分配释放,未释放则在程序结束由操作系统释放 | 利用new开辟。程序运行后 |
意义:灵活编程
堆区开辟空间,程序员手动开辟释放,释放:delete
格式:new 数据类型
new返回的是这个数据类型的指针
#include
using namespace std;
int* func() {
int* a = new int(10);
return a;
}
int main() {
int* p = func();
cout << *p << endl;//*解引用,表示的是值
delete p;//释放堆区数据
system("pause");
}
作用:给变量起别名
格式:数据类型 &别名=原名
注意:引用必须初始化,一旦初始化便不能更改
int a = 10;
int b = 20;
//int &c ;//未初始化
int &c = a;//初始化后不能更改
c = b;//赋值操作,不是更改
3.1)引用做函数参数
作用:让形参修饰实参
优点:简化指针修改实参
void myswap1(int a,int b) {//值传递
int temp = a;
a = b;
b = temp;
}
void myswap2(int* a, int* b) {//地址传递
int temp = *a;
*a = *b;
*b = temp;
}
void myswap3(int &a, int &b) {//引用传递
int temp = a;
a = b;
b = temp;
}
//int a = 10;
//int b = 20;
//myswap1(a,b);//值传递,不改变实参
//myswap2(&a,&b);//地址传递,改变实参
//myswap3(a,b);//引用传递,改变实参
3.2)引用做函数返回值
作用:引用做函数返回值
注意:不要返回局部变量引用
用法:函数调用作为左值
int& text01() {
int a = 10;//局部变量
return a;
}
int& text02() {
static int a = 10;//全局变量
return a;
}
int &c = text01();
cout << c << endl;//第一次结果正确,编译器保留
cout << c;//第二次结果错误,a的内存已经释放
3.3)引用的本质
在c++内部实现一个指针常量
void text02(int& re) {//引用自动转换:int* const re = &a;
re = 100;//转换:*re = 100;
}
void text01() {
int a = 10;
int& tep = a;//引用自动转换:int* const tep = &a;指针常量是指针指向不可更改
tep = 20;//转换:*tep = 100;
cout << a << endl;
cout << tep << endl;
text02(a);
cout << a << endl;
cout << tep << endl;
}
//结果10 10 100 100
3.4)常量引用
作用:防止误操作
格式:const 数据类型& 形参名
4.1)函数默认参数
格式:返回值类型 函数名 (参数 = 默认值){}
注意:①某位置有默认参数,该位置往后必须有默认参数②函数声明有默认参数,函数实现(定义)不能有默认函数
4.2)函数占位参数
形参表里可以有占位参数,用来占位,调用函数时必须填补
格式: 返回值类型 函数名 (数据类型) {}
4.3)函数重载
作用:函数名可以相同,提高复用性
条件:①同一个作用域下②函数名相同③函数参数类型不同或个数不同或顺序不同
注意:函数返回值不可以作为函数重载的条件
注意事项:①引用作为重载条件√②碰到默认参数×会出错
面向对象三大特征:封装、继承、多态
万物皆可为对象
5.1.1)
意义1:
将属性和行为作为一个整体,表型生活中的事物 |
将属性和行为加以控制 |
格式:class 类名{ 访问权限 :属性/行为 };
实例:学生类
class student {//定义学生类
public:
string m_name;
int m_age;
public:
void setstu(string name,int age) {//赋信息的方法
m_name = name;
m_age = age;
}
void showstu() {//显示信息的方法
cout << "姓名:" << m_name << "\t年龄:" << m_age << endl;
}
};
void text() {
student st1;
st1.setstu("张三",18);
st1.showstu();
}
意义2:访问权限
public | 公共权限 | 类内可以访问,类外可以访问 |
protected | 保护权限 | 类内可以访问,类外不可以访问,儿子可以访问父亲保护的内容 |
private | 私有权限 | 类内可以访问,类外不可以访问,儿子不可以访问父亲保护的内容 |
成员属性设置为私有的优点:
5.1.2)struct与class的区别
默认的访问权限不同:
出厂设置...删除数据
5.2.1)构造函数与析构函数
对象或变量未初始化,对其使用后果未知
使用完的对象和变量未及时清理,有安全问题
构造函数与析构函数解决上述。编译器自动调用,我们不提供,系统自动提供空实现
构造函数 | 创建对象时为对象的成员属性赋值 |
析构函数 | 在对象清理前自动调用,执行清理工作 |
构造函数语法:类名(){}
析构函数语法:~类名(){}
如上述例子的学生类中:student st1;//为栈上数据,在执行完text()后,释放这个对象
5.2.2)构造函数的分类与调用
两种分类方式:
Person(const Person &p){//拷贝构造
//将传入的人身上的所以属性,拷贝到我的身上
m_age = p.age;
}
三种调用方式:
Person p1;//默认构造函数,不要写(),否则会认为是一个声明
Person p2(10);//有参构造
Person p3(p2);//拷贝构造
Person p1;
Person p2 = Person(10);
Person p3 = Person(p2);
Person(10);//匿名构造,特点:当前行执行完,系统会立即回收匿名函数,即马上析构
//不要用拷贝构造初始化匿名对象,如:Person(p3);
Person p4 = 10;//相当于Person p4 = Person(10);
Person p5 = p4;
5.2.3)拷贝函数的调用时机
3情况:
void dowor(Person p){//第二种
}
void text02(){
Person p2;
dowor(p2);
}
//第三种
Person dowoo(){
Person p3;
//cout<<(int*)&p3<
5.2.4)构造函数的调用规则
默认,c++编译器至少给一个类添加3个函数
构造函数调用规则如下:
5.2.5)深拷贝,浅拷贝
浅拷贝 | 简单拷贝 | (自己理解)如果开辟了空间,拷贝仍然指向同一个堆中区域、空间的值,在某一方释放该空间时会让另一方出错(重复释放) |
深拷贝 | 在堆区重新申请空间,进行拷贝(new) | 再开辟空间(重构拷贝用深拷贝解决浅拷贝问题) |
析构代码:将堆区开辟的数据做释放操作
m_heig = new int(heih);//再开辟
~Person(){
if(m_heig != NULL){
delete m_heig;
m_heig = NULL;
}
}
例子:
class person {
public:
person(){
cout << "无参构造" << endl;
mage = 0;
mhhhe = 0;
}
person(int age, int hhhe) {
cout << "有参构造" << endl;
mage = age;
mhhhe = new int(hhhe);
}
person(const person& p) {
cout << "拷贝构造" << endl;
mage = p.mage;
//mhhhe = p.mhhhe;//浅拷贝,默认拷贝
mhhhe = new int(*p.mhhhe);//深拷贝,重构拷贝
}
~person() {
if (mhhhe != NULL) {
delete mhhhe;
mhhhe = NULL;
}
cout << "析构函数" << endl;
}
public:
int mage;
int *mhhhe;
};
void text() {
person p1(10,20);
cout << p1.mage << endl;
cout << *p1.mhhhe << endl;
person p2(p1);
cout << p2.mage << endl;
cout << *p2.mhhhe << endl;
}
浅拷贝(默认拷贝会发生问题)
5.2.6)初始化列表
作用:初始化属性
格式:构造函数():属性(值1),属性(值2)...{}
Person(int a,int b):ma(a),mb(b)//初始化列表
{}//初始化列表
int ma;
int mb;
};//上面是在类内
Person p(10,20);//调用
5.2.7)类对象做类成员
例:
class A{}
class B{
A a;
}
//我拿我的手机
//a构造--b构造--b析构--a析构
5.2.8)静态成员
静态成员就是在成员变量或成员函数前加关键字static
静态成员变量 | 所有对象共用一份数据 在编译阶段分配数据 类内声明,类外初始化 |
静态成员函数 | 所有对象共用一个函数 静态成员函数只能访问静态成员变量 |
class person {
public:
static int ma;//类内声明
};
int person::ma = 100;//类外定义(初始化)
静态成员的访问2种方式
void text() {
//1,创建对象
person p1;
cout << p1.ma << endl;
//2,通过类名
cout << person::ma << endl;
}
静态成员也有访问权限,不同权限下,访问结果不同;
5.3.1)成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上,占对象空间。静态成员变量,成员函数(一个函数实例)都不占
c++会为每个空对象分配一个空间
5.3.2)this指针概念
解决5.3.1中代码如何区分一个函数实例问题,(如何知道是自己的函数)
this指针指向被调动的成员函数所属的对象。(谁调用指谁)
this指针是隐含在每一个非静态成员函数内的一种指针
不需要定义,直接使用
用途:
当形参和成员变量同名时,可以用this区分
在类的非静态成员函数中返回对象本身,可以用return *this
5.3.3)空指针访问成员函数
空指针也可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断代码健全性
if (this == NULL) {
return;
}
5.3.4)const修饰成员函数
常函数 | 成员函数加上const后称为常函数 常函数不可修改成员属性 成员属性声明时加关键字mutable后,在常函数中依旧可以修改 |
常对象 | 声明(实例)对象前加const称为常对象 常对象只能调用常函数 |
有些私属性,可让类外特殊的一些函数或类访问
让一个函数或类访问另一个类中私有成员
友元关键字:friend
友元的三种实现
全局函数做友元 |
类做友元 |
成员函数做友元 |
对已有的运算符重新定义,赋予其另一种功能,以适应不同的数据类型(自定义类型)
关键字:operator
//例 加法
class jia1 {
public:
int a ;
//通过成员函数重载
jia1 operator+ (jia1 jiaa) {//对应j5
jia1 temp;
temp.a = jiaa.a + this->a;
return temp;
}
};
jia1 jiafacongzai(jia1 jiaa, jia1 jiaaa) {//以函数方式,对应j4
jia1 temp;
temp.a = jiaa.a + jiaaa.a;
return temp;
}
//通过全局函数重载
//jia1 operator+(jia1 jiaa, jia1 jiaaa) {//关键字operator可简化函数名不写,对应j5
// jia1 temp;
// temp.a = jiaa.a + jiaaa.a;
// return temp;
//}
void jia() {
jia1 j1;
j1.a = 10;
jia1 j2;
j2.a = 20;
jia1 j3;
j3.a = j1.a + j2.a;//普通加法
cout << j3.a << endl;
jia1 j4;
j4 = jiafacongzai(j1, j2);
cout << j4.a << endl;
jia1 j5 = j1 + j2;
}
另:c++编译器给一个类添加4个函数
默认构造函数,无参,函数体为空
默认析构函数,无参,函数体为空
默认拷贝函数,无参,对属性进行值拷贝
赋值运算符operator=,对属性进行值拷贝
面向对象的三大特性之一
5.6.1)
优点:减少重复代码
格式:class 子类:继承方式 父类
子类又名派生类,父类又名基类
子类成员:
继承方式:
|
|
|
|
|
|
|
|
|
父类中继承过来的属性:
|
|
|
|
|
|
继承的构造和析构顺序:
继承同名处理方式:(通过子类访问时)
子类出现父类同名的成员函数,会隐藏父类的
多继承:
菱形继承:
两个派生类b'c继承同一个基类a,又有某个类c同时继承两个派生类
菱形继承问题:基类a中的某份数据会重复继承
解决方法,虚继承:在继承之前加上关键字virtual
class A{};
class B:virtual public A{};
class c:virtual public A{};
//
面向对象的三大特性之一
分为两类 :
静态多态 | 函数重载和运算符重载属于静态多态,复用函数名 | 的函数地址早绑定:编译阶段确定函数地址 |
动态多态 | 派生类和虚函数运行时多态 | 的函数地址晚绑定:运行阶段确定函数地址 |
动态多态满足条件:
动态多态的使用:
多态优点:
例
class Animal {
public:
virtual void move() {//缺少virtual的时候,结果都为“动物在走”
cout << "动物在走" << endl;
}
};
class cat :public Animal {
public:
void move() {
cout << "猫在走猫步" << endl;
}
};
class big :public Animal {
public:
void move() {
cout << "猪在跳舞" << endl;
}
};
void moveaaa(Animal& animal) {
animal.move();
}
void text() {
cout << "zhixin " << endl;
cat cat1;
moveaaa(cat1);
big big1;
moveaaa(big1);
}
纯虚函数/抽象类:
抽象类特点:
virtual void move() = 0;
虚析构和纯虚析构:
多态使用时,如果子类中有属性开辟到堆区,那么父类在释放时无法调用到子类的析构代码
Animal * animal = new Cat("tom");//这种情况下
解决方法:将父类中的析构函数改为虚析构或纯虚析构
虚析构和纯虚析构共性:
虚析构和纯虚析构区别:
虚析构格式:
纯虚析构格式:
程序运行产生的数据属于临时数据,程序一旦运行结束都会被释放,通过文件可以将数据持久化
C++中对文件操作需要包含头文件
文件类型分两类:
文本文件 | 文件以文本的ASCLL码的形式存储在计算机内 |
二进制文件 | 文件以文本的二进制的形式存储在计算机内,用户一般不能读懂 |
操作文件的三大类:
ofstream | 写操作 |
ifstream | 读文件 |
fstream | 读写操作 |
6.2.1)写文件:
文件打开方式:
打开方式 | |
ios::in | 为读而打开文件, |
ios::out | 为写而打开文件,会删除原来的内容 |
ios::ate | 初始位置:文件尾,会删除原来的内容 |
ios::app | 追加方式写文件 |
ios::trunc | 如果文件存在先删除,再创建 |
ios::binary | 二进制方式 |
注意:文件打开方式可以配合使用,利用|操作符
例:用二进制方式写文件ios::binary| ios::out
6.2.2)读文件:
//打开文件判断是否成功
//ifs.open(...);
if(!ifs.is_open())
{
cout<<"文本打开失败"<
有4种读数据方式:
①
char buf[1024] = { 0 };
while (ifs >> buf) {
cout << buf << endl;
}
②
char buf[1024] = { 0 };
while (ifs .getline(buf,sizeof(buf))) {
cout << buf << endl;
}
③
string buf;
while (getline(ifs,buf)) {
cout << buf << endl;
}
④好像读不到汉字
char c;
while ((c=ifs.get())!=EOF) {
cout << c << endl;
}
以二进制的方式对文本进行 读写操作
打开方式要指定为ios::binary
6.3.1)写文件
主要利用流对象调用成员函数write
函数原型:ostre write (const char* buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数。
//片段
Person p={"张三",18};
ofs.write((const char*)&P,sizeof(Person));
6.3.2)读文件
主要利用流对象调用成员函数read
函数原型:istream& write (const char* buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数。
//片段
Person P;
ifs.read((char *)&P, sizeof(Person));