C++学习日记
\t 是转义字符,意思是 制表符(tab),相当于在字符串中插入一个水平空格对齐。中间会有一个对齐的“跳格”,通常相当于 4 或 8 个空格(具体取决于终端或编辑器设置)。
#include <ctime>
:作用是提供 日期和时间 相关的函数,比如:
time()
:获取当前的时间戳(秒数)。localtime()
:把时间戳转成当前时区的时间结构体。strftime()
:格式化时间输出。
C++核心编程
1内存分区模型
C++程序在执行时,将内存大方向划分为4个区域
- 代码区:存放函数体的二进制代码,由操作系统进行管理的。
- 全局区:存放全局变量和静态变量以及常量。
- 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等。
- 堆区:由程序员分配和释放,若程序员不释放程序结束时由操作系统回收。
内存四区意义:
不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。
1.1程序运行前
在程序编译后,生成了.exe可执行程序,未执行该程序前分为两个区域
代码区:
存放CPU执行的机器指令
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区:
全局变量和静态变量存放在此。
全局区还包含了常量区,字符串常量和其他常量也存放在此。
该区域的数据在程序结束后由操作系统释放。
总结:
- C++中在程序运行前分为全局区和代码区
- 代码区特点是共享和只读
- 全局区中存放全局变量、静态变量、常量
- 常量区中存放const修饰的全局常量和字符串常量
1.2程序运行后栈区:
由编译器自动分配释放,存放函数的参数值,局部变量等
注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。
堆区:由程序员分配释放,若程序员不释放,程序结束时由操作系统回收
在C++中主要利用new在堆区开辟内存#include<iostream> using namespace std; int * func {//利用new关键字可以将数据开辟到堆区//指针 本质也是局部变量,放在栈上,指针保存的数据是放在堆区int * p = new int (10);return p; }int main() {//在堆区开辟数据int *p= func();cout << *p << endl;cout << *p << endl;cout << *p << endl;cout << *p << endl;system("pause");}
总结:
堆区数据由程序员管理开辟和释放。
堆区数据利用new关键字进行开辟内存。
1.3 new操作符C++中利用new操作符在堆区开辟数据
堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete
语法:new 数据类型
利用new创建的数据,会返回该数据对应的类型的指针.基本语法
int* func() {int* a= new int(10);return a; } int main() {int *p = func();cout << *p << endl;cout << *p << endl;//利用delete释放堆区数据delete p;//cout<< * p << endl;//报错,释放的空间不可访问system("pause"); }
开辟数组
//堆区开辟数组 int main() {int* arr = new int[10];for (int i=e; i<10; i++)arr[i]=i+100;for (int i=e; iく10; i++)cout << arr[i]<< endl;//释放数组delete后加[]delete[] arr;system("pause");return 0; }
2、引用2.1引用的基本使用
作用:给变量起别名
语法:数据类型 &别名 = 原名int main() {int a =10;int &b = a;cout << "a = " << a << endl;cout << “b = " << b << endl;b =100;cout << "a = "<< a << endl;cout << "b = "<< b << endl;system("pause");return 0; }
2.2引用注意事项
- 引用必须初始化
- 引用在初始化后,不可以改变
示例:
int main() {int a=10;int b = 20;//int &c; //错误,引用必须初始化int &c=a;//一旦初始化后,就不可以更改c = b;//这是赋值操作,不是更改引用cout << "a= " <<a<<endl;cout << "b = " << b << endl;cout << "c = " << c << endl;system("pause");return 0; }
2.3引用做函数参数作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参//1、值传递 void mySwape1(int a,int b){int temp = a;a=b;b =temp; }//2,地址传递 void mySwape2(int* a,int* b){int temp =*a;*a=*b;*b =temp; }//3.引用传递 void mySwape3(int& a, int& b) {int temp = a;a=b;b=temp; }int main() {int a=10;int b =20;mySwap01(a, b);cout << "a:" << a << " b: " << b << endl;mySwap02(&a,&b);cout << "a:" << a<< " b:" << b << endl;mySwape3(a, b);cout << "a:" <da << " b:" << b << endl;system("pause");return 0; }
总结:通过引用参数产生的效果同按地址传递是一样的,引用的语法更清楚简单。
2.4引用做函数返回值作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量引用
用法:函数调用作为左值//返回局部变量引用 int& test01() {int a=10;//局部变量return a; }//返回静态变量引用 int& test02() {static int a = 20;return a; }int main() {//不能返回局部变量的引用int& ref = test01();cout << "ref = "<< ref << endl;//第一次结果正确,是因为编译器做了保留cout << "ref =" << ref << endl;//第二次结果错误,因为a的内存已经释放//如果函数做左值,那么必须返回引用int& ref2 =test02();cout << "ref2 = "<< ref2 <<endl;cout <<"ref2 = "<< ref2 << endl;test02()= 1000;cout << "ref2 = " << ref2 << endl;cout << "ref2 = " << ref2 << endl;system("pause");return 0; }
2.5 引用的本质本质:引用的本质在c++内部实现是一个指针常量。
结论:++推荐用引用技术,因为语法方便,引用本质是指针常量,但是所有的指针操作编译器都帮我们做了.
2.6 常量引用作用:常量引|用主要用来修饰形参,防止误操作
在函数形参列表中,可以加const修饰形参防止形参改变实参//引用使用的场景,通常用来修饰形参 void showValue(const int& v) {//V += 10;cout << v<< endl; }int main() {//int &ref=10;引用本身需要一个合法的内存空间,因此这行错误//加入const就可以了,编译器优化代码,int temp =10;const int &ref = temp;const int& ref =10;//ref = 100;//加入const后不可以修改变量cout << ref << endl;//函数中利用常量引用防止误操作修改实参int a=10;showValue(a);system("pause");return 0; }
3、函数提高3.1函数默认参数
在C++中,函数的形参列表中的形参是可以有默认值的。
语法:返回值类型函数名(参数=默认值){ }注意事项
1、如果某个位置己经有了默认参数,那么从这个位置往后,从左到右都必须有默认值。
2、如果函数声明有默认参数,函数实现就不能有默认参数。声明和实现只能有一个有默认参数int func(int a,int b =10, int c = 10) {return a + b+ c; }//1,如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值//2,如果函数声明有默认值,函数实现的时候就不能有默认参数int func2(int a=10,int b=10);int func2(int a,int b) {return a + b; }int main() {cout << "ret = " << func(20,20)<< endl;cout << "ret =" << func(100)<< endl;system("pause");return 0; }
3.2函数占位参数C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法:返回值类型 函数名(数据类型) { }
在现阶段函数的占位参数存在意义不大,但是后面的课程中会用到该技术。//函数占位参数,占位参数也可以有默认参数 void func(int a,int) {cout << "this is func" << endl;int main(){func(10,10);//占位参数必须填补system("pause");return 0; }
3.3 函数重载3.3.1函数重载概述
作用:函数名可以相同,提高复用性
函数重载满足条件:
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同或者个数不同或者顺序不同
注意:函数的返回值不可以作为函数重载的条件。
//函数重载需要函数都在同一个作用域下 void func() {cout<"func的调用!"<<endl; } void func(int a) {cout<<"func(int a)的调用!"<<endl; } void func(double a) {cout <<"func (double a)的调用! " << endl; } void func(int a ,double b) {cout<<"func(int a ,double b)的调用! "<< endl; }void func(double a,int b) {cout <<"func (double a,int b)的调用! "<< endl; }//函数返回值不可以作为函数重载条件 //int func(double a,int b) //{ // cout<<"func(double a,int b)的调用!"<<endl; //}int main() {func();func(10);func(3.14);func(1p,3.14);func(3.14,10);system("pause");return 0; }
3.3.2函数重载注意事项
- 引用作为重载条件
- 函数重载碰到函数默认参数
//函数重载注意事项 //1、引用作为重载条件 void func(int_&a) {cout << "func(int &a)调用 "<< endl; }void func (const int &a) {cout <<"func (const int &a)调用"<<endl; }//2、函数重载碰到函数默认参数 void func2(int a,int b =10) {cout<<"func2(int a,int b=1o)调用" << endl; } void func2(int a) {cout<"func2(int a)调用"<<endl; }int main() {int a=10;func(a);//调用无constfunc(10);//调用有const//func2(10;//碰到默认参数产生歧义,需要避免system("pause");return 0; }
4类和对象C++面向对象的三大特性为:封装、继承、多态
C++认为万事万物都皆为对象,对象上有其属性和行为
例如:
人可以作为对象,属性有姓名、年龄、身高、体重..,行为有走、跑、跳、吃饭、唱歌..
车也可以作为对象,属性有轮胎、方向盘、车灯行为有载人、放音乐、放空调...
具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类
4.1 封装4.1.1封装的意义
封装是C++面向对象三大特性之一
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
封装意义一:
在设计类的时候,属性和行为写在一起,表现事物
语法:class 类名 { 访问权限 : 属性 / 行为 };
示例1:设计一个圆类,求圆的周长//圆周率 const double PI = 3.14;//1、封装的意义 //将属性和行为作为一个整体,用来表现生活中的事物 //封装一个圆类,求圆的周长 //class代表设计一个类,后面跟着的是类名 class Circle { public://访问权限 公共的权限//属性int m_r;//半径//行为//获取到圆的周长double calculatezc(){//2 * pi * r//获取圆的周长return 2 * pI * m_r;}};int main() {//通过圆类,创建圆的对象//c1就是一个具体的圆Circle c1;c1.m_r = 10;//给圆对象的半径 进行赋值操作//2 * pi * 10 == 62.8cout<<"圆的周长为: “<<c1.calculatezc()<<endl;system("pause");return 0; }
示例2:设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号//学生类 class Student { public:void setName(string name){m_name = name;}void setID(int id){m_id=id;}void showStudent(){cout << "name:" << m_name << " ID:" << m_id<< endl;}public: {string m_name;int m_id; } int main() {Student stu;stu.setName("德玛西亚");stu.setID(250);stu.showStudent();system("pause");return 0; }
封装意义二:类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限有三种:
- public 公共权限
- protected 保护权限
- private 私有权限
//三种权限 //公共权限 public 类内可以访问 类外可以访问 //保护权限 protected 类内可以访问 类外不可以访问 //私有权限 private 类内可以访问 类外不可以访问class Person {//姓名 公共权限 public:string m_Name;//汽车 保护权限 protected:string m_Car;//银行卡密码 私有权限 private:int m_Password;public:void func(){m_Name = "张三";m_Car="拖拉机";m_Password = 123456;};int main() {Person p;p.m_Name ="李四";p.m_Car = "摩托车";p.m_Password = 1412;system("pause"):return 0;}
4.1.2 struct和class区别在C++中struct和class唯一的区别就在于默认的访问权限不同
区别:
- struct默认权限为公共
- class默认权限为私有
class C1 {int m_A;//默认是私有权限 };struct C2 {int m_A;//默认是公共权限 };int main() {C1 c1;c1.m_A=10;//错误,访问权限是私有C2 c2;c2.m_A=10;//正确,访问权限是公共system("pause");return 0; }
4.1.3成员属性设置为私有优点1:将所有成员属性设置为私有,可以自己控制读写权限。
优点2:对于写权限,我们可以检测数据的有效性。
练习案例2:点和圆的关系
设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系。