63 阅读15分钟

一.常量定义的方式

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;

}