一.常量定义的方式
1.常量:#define 常量 常量值(不可以改变,一般定义在文件上方)。
2.const修饰的变量为常量不可修改。
3.关键字=标识符。
二.语法
1.利用sizeof来求数据类型占用内存大小。
:sizeof(数据类型/变量)
2. 实型:单精度 float,双精度 double
细节:当单精度 float没有加’f’时会自动转化为double。
eg.float f1=3.14f;
3. 科学记数法:
float f2=3e2:(如果e后的数是负数则为0.1^2) //3*10^2
4.NULL什么也没有
10.18
字符串类型
1. #include为C++风格的字符串所要包含的头文件。
c:char str []=”hello world”;
count<<str<<endl;
c++:string str=”hello world”;
count<<str<<endl;
布尔类型bool
1. 作用:布尔数据类型代表真或假的值。
2. 仅有两种:true真(1),false假(0)。
3. 所占的内存空间为1个字节。
数据的输出(键盘录入)
1. 整型
Int a=0;
cout<<”请给整形变量a赋值<<endle;
Cin>> a;
Cout<<”a的值为:”<<endle;
2. 浮点型
不加f系统默认为双精度
3. 字符型
char ch=’a’;
//说明
cin>>ch;
4. 字符串型
注意在进行字符串型赋值时要加:#include (包含string的头文件)
string str=”hello”;
cin>>str;
5. 布尔类型
只要是非0的值都代表真(NULL什么也没有)
运算符
1. 算术运算符:
+:正号或加
-:负号或减法
*:乘法
/:除法
%:取模(取余)
++:递增(前置或后置)
--:递减(前置或后置)
程序流程结构
1. 顺序结构:程序按顺序执行,不发生跳转
2. 选择结构:依据条件是否满足,有选择的执行相印功能
3. 循环结构:依据条件是否满足,循环多次执行某段代码
选择结构
1. if后面不可以加分号 ,break用于退出当前循环。
2. switch执行时要加break要不然会导致case穿透即在遇到下一个break时其不会停止执行,最后用default。注意switch的括号中只能放一个整型或字符型,不可以是一个区间其执行效率更高。
循环结构
1. while(循环条件){循环语句}:循环条件为真则执行循环语句。还可以无限循环while(1)
#include
using namespace std;
int main()
{
int num = 0;
while (num < 10)
{
num++;//结果从1开始
cout << num << endl;
num++;//结果从0开始
}
system("pause");//pause:暂停
return 0;
}
2. 猜数字(获取一个种子)srand((unsigned int)time(NULL));【要加#include】
3. do...while:与while的区别在于其会先执行一次循环语句,再判断循环条件。
语法:do{循环语句}while(循环条件);
eg.
int num=0;
do
{
cout<<num<<endl;
num++;
}
while(num<10);
结构体
#include
using namespace std;
#include
// 定义结构体student
struct student {
string name;
int age;
int score;
}; // 移除这里的student,因为它被误用为变量声明
// 通过值传递的打印函数
void printStudent1(struct student s) {
//修饰形参实参不改变
s.age = 200;
cout << "子函数 姓名:" << s.name << " 年龄:" << s.age << " 成绩:" << s.score << endl;
}
// 通过指针(地址)传递的打印函数(虽然被注释掉了,但提供正确的实现方式)
void printStudent2(struct student* p) {
//修饰形参实参也改
p->age = 200;
cout << "子函数 姓名:" << p->name << " 年龄:" << p->age << " 成绩:" << p->age << endl;
}
int main() {
struct student s; // 创建一个student结构体变量s
s.name = "张三";
s.age = 18;
s.score = 100;
// 在main函数中打印学生信息,注意添加空格以提高可读性
cout << "main函数打印 姓名:" << s.name << " 年龄:" << s.age << " 成绩:" << s.score << endl;
// 调用通过值传递的打印函数
printStudent1(s);
// 如果需要,可以取消下面这行代码的注释来使用通过指针传递的打印函数
// printStudent2(&s);
system("pause");
return 0;
}
3. const的使用场景:
将函数的形参改为指针,可以减少内存空间,而且不会复制新的副本出来
void printStudent1(struct student s){
s.age=18;
cout<<....<<endl;
}
变为:
void printStudent1( student *s){
s->age=18;
cout<<....<<endl;//s->age
}
为防止误操作(即在函数中将变量改变了)可以在 student 前加const
C++核心编程
<程序运行之前>->1.,2. c-const g-global l-local
<程序运行之前>->3.,4.
四区意义:不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。
1.代码区:存放函数体的二进制代码,由操作系统进行管理的。
存放CPU执行的机器指令(二进制代码)。
代码区是共享的,目的是对于重复执行的程序,只需要在内存中有一份代码就可以。
代码区是只读的,使其只读的原因防止程序意外地修改了它的指令。
2.全局区:存放全局变量和静态变量以及常量。
全局变量和静态变量存放在此。
还包含了常量区,字符串常量和其他常量:const也存放在此。
该区域的数据在程序结束后由操作系统释放。
全局变量 静态变量 常量。
01.在main中的是局部变量。
02.静态变量在数据类型前加static。
03.常量:
.字符串常量:双引号引起来的字符串
cout<<(int)&”hello world”<<endl;//(int):强制转化
.const修饰的常量:
全局常量:在main函数外的和全局变量放在一起。
局部常量:和局部变量放在一起。
3.栈区:由编译器自动分配释放,存放函数的参数值,局部变量等。
由编译器自动分配释放,存放函数的参数值,局部变量等。
注意:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。
Eg.int*func(int b)//形参数据也会放在栈区
{
b=100;
int a=10;//局部变量 存放在栈区,栈区的数据在函数执行完后自动释放
return &a;//返回局部变量的地址 其中&a与定义的数据类型int*相对应
}
int main()
{
int*p=func(1);
cout <<*p<<endl;//第一次可以打印正确的数字,是因为编译器做了保留
cout <<*p<<endl;//第二次这个数据就不再保留了
理解:该栈区是一次性的,同一个栈不可以用两次
4.堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。
在C++中主要利用new在堆区开辟内存
.在堆区开辟数据:
Eg.int*func()
{
//利用new关键字可以将数据开辟到栈区
//指针 本质也是局部变量,放在栈上,指针保存的数据是放在堆区
int*p=new int (10);
return p;
}
int main()
{
int*p=func();
cout<<*p<<endl;
}
new操作符
1. C++中用new操作符在堆区开辟数据
2. 堆区开辟的数据,由程序员手动开辟,手动释放,释放用操作符delete
语法:new数据类型
.用new创建的数据,会返回该数据对应的类型的指针
.new的基本语法和在堆区如何用new开辟一个数组
int*func()
{
//在堆区创建整型数据
//new返回是 该数据类型的指针
int*p=new int(10);
return p;
}
void test01()
{
//操纵该内存
int *p=func()
cout<<*p<<endl;
//堆区的数据 由程序员管理开辟,程序员管理释放
//如果想释放堆区的数据,利用关键字delete
delete p;
cout<<*p<<endl;//会报错 前一次可以打印
}
开辟一个数组
void test02()
{
//创建10整型数据的数组,在堆区
int *arr=new int[10];//代表数组有10个元素
for(int i=0;i<10;i++)
{
arr[i]=i+100;
}
for(inti=0;i<10;i++)
{
cout<<arr[i]<<endl;
}
//释放堆区数组
//释放堆区数组的时候要加[]才可以
delete[]arr;
}
引用
作用:给变量起别名(操作的是同一块内存)
语法:数据类型&别名=原名
int a=10;
int &b=a;
cout<<a<<endl;//20
注意:引用必须初始化。
引用在初始化后,不可以改变。
1.引用必须初始化
Int a=10;
int &b=a;
//int &b;->是错误的
2.引用在初始化后,不可以改变,即初始化后将b改为了其他别名
eg.#include
using namespace std;
int main()
{
int a = 10;
int &b = a;
int c = 20;
int &b = c;//重复初始化
cout << a << endl;
cout << b << endl;
cout << c << endl;
return 0;
}
引用做函数参数
1. 值传递:形参不会修饰实参
Eg.void mySwap01(int a,int b)
{
int temp=a;
a=b;
b=temp;//其中的形参发生改变了
}
2. 地址传递(用的是指针)
void mySwap02(int a,intb)
{
int temp=*a;
*a=*b;
*b=temp;
}
3. 引用的传递(让形参修饰实参)
void mySwap03(int &a,int &b)
{
int temp=a;
a=b;
b=temp;
}
int main()
{
int a =10;
int b=20;
//mySwap01(a,b);//其中的形参不会修饰实参
//mySwap02(&a,&b);//其中的形参会修饰实参
//mySwap03(a,b);//其中形参会修饰实参
return 0;
}
注意:其中的int &a=a与int &a=b时已经完成了初始化,别名与原名一样。
引用做函数的返回值
1. 不要返回局部变量的引用。
int& text01()
{
int a=10;//局部变量存放在栈区(执行完text01后应该释放)
return a;
}
2. 函数的调用可以作为左值(等号左边的值)
int& text02()
{
static int a=10;//静态变量存放在全局区,全局区上的数据在程序结束后由系统释放
return a;//返回的是a的引用相当于把a的变量(即a本身)作为了返回
}
int main()
{
1. //int &ref=text01();
//cout<<”ref= ”<<ref<<endl;//10可以正常打印->编译器做了一次保留
//cout<<”ref= ”<<ref<<endl;//第二次错误,a的内存已经被释放了
2. int &ref2=text02();//函数调用
cout<<”ref2= ”<<ref2<<endl;//10
text02()=1000;//如果函数的返回值是引用,这个函数的调用可以作为做值
cout<<”ref2= ”<<ref2<<endl;//1000 ref2实际上是a的别名
}
引用的本质->指针常量
:在C++内部实现是一个指针常量(指针指向不可以改,但指针指向的值可以改)
Eg.void func(int& ref)
{
ref=100;
}
int main()
{
int a=10;
//编译器将其自动转化成int *const ref=&a;->也可以解释为什么引用不可以更改
//const限定表示指针的指向是固定的,但其值可以改
int& ref(别名)=a; //可以理解为指针变量的名称为ref其中存放的数据是a的地址
ref=20; //内部发现ref是引用,帮我们自动转化为指针*ref(指针的解引用)=20;
return 0;
}
常量引用
作用(使用场景):常量引用主要用来修饰形参,防止误操作
在函数形参(函数括号里的都是形参)列表中可以加const修饰形参,防止形参改变实参
Eg.void showValue( const int &val)//加上了const value就不可以修改了(不会让参数发生改变)
{
Val=1000;
Cout<<”val= ”<<val<<endl;
}
int main(){
//Int a=10;//堆区
//const int& ref=10;//错误 引用必须引用一块合法的内存空间,这里的10在常量区
加上const 之后编译器将代码修改:int temp=10;const int & ref=temp;指针指向该变量
并且加入了const后变成了只读,不可以修改。
Int a=100;//通过一个函数打印a的值
showValue(a);//a是原名
Cout<<”a= ”<<a<<endl;//1000
函数的提高
一.函数的默认参数
在C++中,函数的形参列表中的形参是可以有默认值的。
语法:返回值类型 函数名 (参数=默认值){}
eg.//函数默认参数
int func(int a,int b,int c)
{
return a+b+c;
}
int main()
{
func(10,20,30);
return 0;
}
注意:
int func(int a,int b=20,int c=30)//其中啊b,c均有默认值
{
return a+b+c;//70传了就用传递的值,没有就用默认值
}
int main()
{
func(10,30);
return 0;
}
注意事项:
1. 如果某个位置已经有了默认参数,那么从这个位置往后,从左到右必须有默认值即参数必须=默认值。
2. 如果函数声明有默认参数,函数实现就不能有默认参数 即:声明和实现只能有一个有默认参数。
二.函数默认参数
1.C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置
语法:返回值 函数名((只写)数据类型){}
Eg.void func(int a,int)//function->函数
{
cout<<”this is func”<<endl;
}
Int main(){
Func(10,10);//必须有第二个10
//目前阶段的占位参数还用不到
//占位参数 还可以有默认参数
}
三. 函数重载
1. 函数重载概述:
作用:函数名可以相同,提高复用性
必须满足的条件:
.同一个作用域下
.函数名称相同
.函数参数类型不同或者个数不同或者顺序不同
注意:函数的返回值不可以作为函数重载的条件
Eg.
//函数重载的满足的条件:
//1.同一个作用域下(满足)
//2.函数名称相同(满足)
//3.函数参数类型不同或者个数不同或者顺序不同(不满足)
.void func()//均在全局作用域
{
cout<<”func的调用”<<endl;
}
.void func((添加)int a)
{
cout<<”func的调用!”<<endl;
}
.void func(double a)
{
cout<<”func(double a)的调用!”<<endl;
}
.void func(int a,double b)
{
cout<<”func的调用”<<endl;
}
int main()
{
.void func(double b,int a)
{
cout<<”func的调用”<<endl;
}
.int func(double b,int a)//报错无法重载按返回值类型区分的函数
{ //函数的返回值类型(的不同)不可以作为函数重载的条件
cout<<”func的调用”<<endl;
}
int main()
{
func ();//根据传入的不同参数可知调用的第一个
func ();//根据传入的不同参数可知调用的第二个
Return 0;
}
函数重载的注意事项:
1. 引用作为重载条件
Void func(int &a)//其中int &a=10是一个非法操作
{
Cout<<“func(int &a)调用”<<endl;
}
Void func( const int &a)//const int &a=10;编译器做了优化
{ //相当于创建了一个变量作为临时存储
Cout<<“func(const int &a)调用”<<endl;//只能读不能写
}
Int main()
{
Int a=10;//其中a是一个变量可以修饰
Func(a);//调用的是第一个
Func(10);//调用的是第二个
}
//类型不同
2. 函数重载碰到函数的默认参数(尽量避免)
. Void func(int a,int b=10)
{
Cout<<“func(int a,int b)调用”<<endl;
}
. Void func(int a)
{
Cout<<“func(int a)调用”<<endl;
}
Int main()
{
Func(10);//当其既可以调一又可以调二时函数报错(b有默认值时)
//出现二义性(func(10,20);可以调用第一个)
Return 0;
}
四. 类和对象
C++面向对象的三大特性:封装,继承,多态
C++认为万事万物都皆为对象,对象上有属性和行为
具有相同性质的对象,我们可以抽象为类
1. 封装
封装的意义:
(1)将属性和行为作为一个整体表现生活中的事物
(2)将属性和行为加以权限控制
1. .将属性和行为作为一个整体表现生活中的事物
语法:class类名{访问权限: 属性/行为};
专业术语:类中的属性和行为 我们统一称为 成员
属性:成员属性 成员变量
行为:成员函数 成员方法
还可以通过行为给属性赋值
Void setName(string name)
{
m_Name=name;
}
}//在class中
Int main()
{
s1.setName(“张三”);
}
Eg.设计一个圆类,求圆的周长
圆的周长的公式:2 *PI *半径
const double PI=3.14;
class Circle
{
//访问权限
//公共权限
public:
//属性
int m_r;
//行为(一般用函数)
//获取圆的周长//函数
double calculateZC()
{
return 2 *PI *m_r;
}
}
int main()
{
//通过圆类 创建具体的圆(对象)
//实例化(通过一个类 创建一个对象的过程)
Circle c1;
//给圆对象的属性进行赋值
c1.m_r=10;
//2 *PI *10=62.8
cout<<”圆的周长为:”<< c1. calculateZC()<<endl;
return 0;
}
(2)将属性和行为加以权限控制
访问权限
1.public 公共权限 成员 类内可以访问 类外可以访问
2.protected 保护权限 成员 类内可以访问 类外不可以访问 儿子可以访问父亲中的保护内容(车子)
3.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 p1;//实例化
p1.m_Name=”李四”;
p1.m_Car=”奔驰”;//报错 保护权限内容,在类内访问不到
//私有也一样,函数也是一样的
return 0;
}
struct与class的区别
在C++中struct和class唯一的区别就在于默认的访问权限不同
区别:
.struct 默认权限为公共 public
.class 默认权限为私有 private//可以用指针进行修改
成员属性设置为私有
优点1:将所有成员属性设置为私有,可以自己控制读写权限
优点2:对于写权限,我们可以检测数据的有效性
Eg.优点1
class Person
{
//提供公有的方法来对私有的属性进行控制
publiic:
//设置姓名
void setName(string nsme)
{
m_Name=name;
}
//获取姓名
string getName()
{
return m_Name;
}
//获取年龄
Int getAge()
{
Return m_Age;
}
//设置年龄
Int getAge()
{
return m_Age;
}
//获取年龄(0~150)
{
if(age<0||age>150)
{
cout<<”年龄”<<age<<”输入有误,赋值失败”<<endl;
return 0;
}
m_Age=age;
}
//设置偶像(外界无法访问)
Void setIdol(string idol)
{
m_Idol=idol;
}
private:
string m_Name;//姓名 可读可写
int m_Age=18;//年龄 只读(不可以修改)(U2.也可以写)
string m_Idol;//偶像 只写(可以写但不可以访问)
}
int main()
{
Person p;
//姓名设置
p.SetName(“张三”);
cout<<”姓名:”<<p.getName()<<endl;
//年龄设置
//p.setAge(20);//没有这个属性
//p.m_Age=20;//私有化无法修改
//获取年龄
cout<<”年龄:”<<p.getAge()<<endl;//只读
//偶像的设置
p.getIdol(“小明”);
//cout<<”偶像:”<<p.getIdol<<endl;//没有这个属性读不到
return 0;
}