C++学习笔记

本文档详细介绍了C++的学习内容,包括指针的定义、使用及与数组、函数的结合,结构体的创建和应用,内存管理,引用的使用规则,函数高级特性如默认参数和重载,类和对象的封装、构造函数、析构函数、拷贝构造和多态,以及文件操作的基础知识。通过对这些核心概念的讲解,帮助读者深入理解C++编程。
摘要由CSDN通过智能技术生成

目录

一、指针

1.1  指针定义语法

1.2  使用指针

1.3  占用空间

1.4  空指针和野指针

1.5  const修饰指针和常量

1.6  指针和数组

1.7  指针和函数

 二、结构体

2.1  创建学生数据类型

2.2  通过学生类型创建具体学生

2.3  结构体数组

2.4  结构体指针

2.5  结构体嵌套结构体

2.6  结构体做函数参数  

2.7  结构体中const使用

三、内存

3.1  内存四区

3.2  new操作符

四、引用

4.1  引用的基本使用

4.2  引用的注意事项

4.3  引用做函数参数 

4.4  引用做函数的返回值

4.5  引用的本质

4.6  常量引用

五、函数高级

5.1  函数默认参数

5.2  函数占位参数

5.3  函数重载

六、类和对象

6.1  封装

6.1.1  封装的意义

6.1.2  struct和class的区别

6.1.3  将成员属性设为私有

设计案例1:立方体类

设计案例2:点和圆的关系

6.2  对象的初始化和清理

6.2.1  构造函数

6.2.2  析构函数

6.2.3  拷贝构造函数调用时机

6.2.4  构造函数调用规则

6.2.5  深拷贝与浅拷贝

6.2.6  初始化列表

6.2.7  类对象作为类的成员

6.2.8  静态成员

6.3  C++对象模型和this指针

6.3.1  成员变量和成员函数分开存储

6.3.2  this指针的概念

6.3.3  空指针访问成员函数

6.3.4  const修饰成员函数

6.4  友元

6.4.1  全局函数做友元

6.4.2  类做友元

6.4.3  成员函数做友元 

6.5  运算符重载

6.5.1  加号运算符重载

6.5.2  左移运算符(<<)的重载

6.5.3  递增运算符的重载

6.5.4  赋值运算符重载

6.5.5  关系运算符的重载

6.5.6  函数调用运算符()重载

6.6  继承

6.6.1  继承的基本语法

6.6.2  继承的方式

6.6.3  继承中的对象模型

6.6.4  继承中构造和析构顺序

6.6.5  继承中同名成员的处理方式

6.6.6  继承同名静态成员处理方式

6.6.7  多继承语法

6.6.8  菱形继承

6.7  多态

6.7.1  多态的基本概念

6.7.2  多态案例----计算器类

6.7.3  纯虚函数和抽象类

6.7.4  多态案例二----制作饮品

6.7.5  虚析构和纯虚析构

6.7.6  多态案例三----电脑组装

七、文件操作

7.1  文本文件

7.1.1  写文件

7.1.2  读文件        

7.2  二进制文件

7.2.1  写文件

7.2.2  读文件


一、指针

1.1  指针定义语法

        数据类型 * 指针变量名 

int a;
int * p;
p = &a;

1.2  使用指针

        可以通过解引用的方式来找到指针指向的内存。
        指针前加 * 代表解引用,找到指针指向的内存中的数据。

1.3  占用空间

        在32位操作系统下:占用四个字节空间
        在64位操作系统下:占用八个字节空间

1.4  空指针和野指针

        空指针用于给指针变量进行初始化
        空指针是不可以进行访问的
        野指针:指针变量指向非法的内存空间
        空指针和野指针都不是我们申请的空间,因此不要随意访问。

1.5  const修饰指针和常量

        const修饰指针------常量指针
        指针的指向可以修改,但是指针指向的指不可以改。
        const  int  * p=&a;     

        const修饰常量------指针常量
        指针的指向不可以改,但是指针指向的值可以改。
        int * const p=&a;    

        const即修饰指针又修饰常量
        指针的指向和指针指向的值都不可以改。
        const int * const p=&a;

1.6  指针和数组

int main() {
    //指针和数组
    //利用指针访问数组中的元素
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    cout << "第一个元素为:" << arr[0] << endl;
    int* p = arr; / /arr就是数组首地址
    cout << "利用指针访问第一个元素:" << *p << endl;
    p++;//让指针向后偏移4个字节
    cout << "利用指针访问第二个元素:" << *p << endlsm
}
cout << ”利用指针遍历数组"<<endl;
int* p2 = arr;
for (int i = 0; i < 10; i++) 
{
    //cout << arr[i] << endl;
    cout<<*p2<< end1;
    p2++;
}

1.7  指针和函数

        值传递

void swap01(int a,int b)

        地址传递

void swap02(int *p1,int *p2)           

 二、结构体

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

2.1  创建学生数据类型

struct Student{
                string name;    //姓名
                int age;    //年龄
                int score;        //分数
            };

2.2  通过学生类型创建具体学生

        (创建时struct 关键字可以省略,定义时不能)

struct Student S1;            //Student S1  也可
S1.name = "张三";
S1.age = 18;
S1.score = 100;
struct Student S2 = {"李四",19,80};
//定义结构体时顺便创建结构变量    
struct Student{
    string name;    //姓名
    int age;    //年龄
    int score;        //分数
}S3;        //顺便创建结构体变量,S3就是结构体变量
            
S3.name = "张三";
S3.age = 18;
S3.score = 100;

2.3  结构体数组

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

​//1.定义结构体
            
            struct Student{
                string name;    //姓名
                int age;    //年龄
                int score;        //分数
            };  

int main(){            
    
//2.创建结构体数组
            struct Student stuArray[3] = {
                {"张三",18,100},
                {"李四",28,99},
                {"王五",38,166},
            };
//3.给结构体数组中的元素赋值
            stuArray[2].name = "赵六";
//4.遍历结构体数组
            for(int i = 0 ; i < 3 ; i++)
            {
            cout    <<"姓名:"<<stuArray[i].name
                    <<"年龄:"<<stuArray[i].age
                    <<"成绩:"<<stuArray[i].score<<endl;
            }
}

2.4  结构体指针

        利用操作符->可以通过结构体指针访问结构体属性

//1.定义结构体
            
            struct Student{
                string name;    //姓名
                int age;    //年龄
                int score;        //分数
            };    
    
int main(){
//1.创建学生结构体变量      
            struct Student s = {"张三",18,100};        //struct可省略

//2.通过指针指向结构体变量
            struct Student * p = &a;        //struct可省略

//3.通过指针访问结构体变量中的数据
            cout<<"姓名:"<< p->name <<"年龄:"<< p->age <<"成绩:"<< p->score;
}

2.5  结构体嵌套结构体

#include<iostream>
#include<string>
using namespace std;
//学生结构体
struct student {
    string name;
    int age;
    int score;
};
//老师结构体
struct teacher {
    int id;
    string name;
    int age;
    struct student stu;  //辅导的学生
};

int main()
{
    teacher t;
    t.age = 50;
    t.id = 10000;
    t.name = "老王";
    t.stu.name = "小王";
    t.stu.age = 18;
    t.stu.score = 100;
    cout << "老师姓名:" << t.name<<endl << "学生姓名:" << t.stu.name<<endl;
    system("pause");
    return 0;
}

2.6  结构体做函数参数  

#include<iostream>
#include<string>
using namespace std;
//学生结构体
struct student {
    string name;
    int age;
    int score;
};
void printstudent1(struct student s)// 值传递
{
    cout << "子函数1中 姓名:" << s.name << endl;
}
void printstudent2(struct student* p)//地址传递
{
    cout << "子函数2中 姓名:" << p->name << endl;
}

int main()
{
    student s;
    s.name = "张三";
    s.age = 20;
    s.score = 85;
    printstudent1(s);
    printstudent2(&s);
    return 0;
}

2.7  结构体中const使用

void print(const student *p )    //p的值无法被修改,类似实参形参,不过指针只传递地址,参数要传输大量数据,节省了空间.加入const之后一旦有修改操作就会报错

三、内存

3.1  内存四区

        C++程序在执行时,将内存大方向划分为4个区域:  
                ·代码区:存放函数体的二进制代码,由操作系统进行管理的
                ·全局区:存放全局变量和静态变量以及常量
                ·栈区:由编译器自动分配释放,存放函数的参数值,局部变量等
                ·堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

        内存四区意义:
                不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程

        程序运行前:
                代码区:存放函数体的的二进制代码,操作系统管理。
                特点: ①共享 :对于频繁被执行的程序,只需要在内存中有一份代码即可。
                            ②只读:目的是防止程序意外地修改了它的指令。

                全局区:存放全局变量、静态变量(stati关键字)和常量(字符串常量和const修饰的全局变量(全局常量))。
                不在全局区中:局部变量、const修饰的局部变量(局部常量)

//全局变量
int g_a = 10;
const int c_g_a = 10;
int main()
{
	int l_a = 10;
	//静态变量
	static int s_a = 10;
	
	//常量:字符串常量/const修饰的变量(全局/局部变量)
	const char* a = "hello";
	const int c_l_a = 10;

	cout << "局部变量l_a的十进制地址为:" << (int)&l_a << endl;
	cout << "全局变量g_a的十进制地址为:" << (int)&g_a << endl;
	cout << "静态变量s_a的十进制地址为:" << (int)&s_a << endl;
	cout << "字符串常量a的十进制地址为:" << (int)a << endl;
	cout << "const修饰的全局变量c_g_a的十进制地址为:" << (int)&c_g_a << endl;
	cout << "const修饰的局部变量c_l_a的十进制地址为:" << (int)&c_l_a << endl;
	return 0;

}

在这里插入图片描述

        程序运行后:
                栈区:存放函数的参数值、局部变量。由编译器自动分配和释放。
                注意事项:不要返回局部变量地址
                形参数据也会放在栈区

int* funcation()
{
	int a = 10;//存放在栈区,栈区的数据在函数执行完后自动释放
	return &a;
}
int main()
{
	int* p = funcation();
	cout <<"局部变量a的值为:"<< *p << endl;  //第一次正常打印,因为编译器做了保留
	cout << "局部变量a的值为:" << *p << endl;
	return 0;
}

在这里插入图片描述

        堆区:由程序员分配(new)和释放(delete),若程序员不释放,程序结束时由操作系统回收。 

int* funcation()
{
	//new关键字,可以将数据开辟到堆区上
	//指针本质上也是局部变量,存放在栈区上,但是保存的数据在堆区
	int* p = new int(10); //返回的是地址,不是数据
	return p;
}
int main()
{
	int* p = funcation();
	cout << *p << endl;
	cout << *p << endl;
	return 0;
}

        在c++中主要利用new在堆区开辟内存

3.2  new操作符

//new的基本用法
int* p = new int(10);//在堆区创建整型变量,返回该变量的地址
delete p;//释放
int* parr = new int[10];//在堆区创建一个元素为10的整型数组,返回数组首元素的地址
delete[] arr;//释放一个数组 

        在堆区利用new开辟数组        

int * arr= new int[10];
for(int i=0;i<10;i++)
{
	arr[i]=i+100;
}

        释放堆区数组

delete[] arr;

四、引用

4.1  引用的基本使用

        引用:给变量起个别名。

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

int a=10;
int &b=a;

4.2  引用的注意事项

        1.引用必须要初始化

        2.引用一旦初始化后就不可以更改

int a = 10;
int& b = a;
int c = 20;
b = c;
cout << a << endl;
cout << b << endl;
cout << c << endl;
//int& b = c; //错了!!!

4.3  引用做函数参数 

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

        优点:可以简化指针修改实参

//地址传递
void swap01(int* a, int* b)
{
	int temp = *a;
	*a = *b;
	*b = temp;
}
//引用传递
void swap02(int& a, int& b)
{
	int temp = a;
	a = b;
	b = temp;
}

4.4  引用做函数的返回值

        注意:不要返回局部变量的引用,函数的调用可以作为左值。(局部变量存放在栈区,函数执行完后自动释放局部变量,可以加上static是数据存放在全局区,就可以返回了)

//eg.
//①不要返回局部变量的引用
int& test1()
{
	int a = 10;
	return a;
}
int main()
{
	int& ret = test1();
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	test1() = 20; //②如果函数的返回值为引用,函数的调用可以作为左值
	cout << "ret=" << ret << endl;
	cout << "ret=" << ret << endl;
	return 0;
}

4.5  引用的本质

        本质:引用的本质在c++内部实现是一个指针常量(指针的指向不可以修改,指针指向的值可以修改),即 引用的本质就是一个指针常量,引用一旦初始化后就不可发生改变

int& ref = a;
//自动转换为 int* const ref = &a;指针常量是指针指向不可改,也说明为什么引用不可改

4.6  常量引用

        常量引用主要用来修饰形参,防止误操作。(防止修改了形参引起了实参的改变,加上const之后,修改操作会报错,不能修改)

int &ret=10; //错了!,引用本身需要一个合法的内存空间。
/*
相当于编译器先创建一个临时变量:int temp=10;
然后进行起别名:int& ret=temp;
*/
const int& ret = 10;

        注意:用常量引用之后不可以更改数据。 

//eg.
int main()
{
	const int& ret = 10;
	ret = 100;//err
	cout << "ret=" << ret << endl;
	return 0;
}

在这里插入图片描述

五、函数高级

5.1  函数默认参数

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

        注意事项:

                如果某个位置已经有了默认参数,那么从这个位置往后,从左到右都必须有默认值。

                如果函数的声明有默认参数,函数实现就不能有默认参数。(编译器不知道用哪个参数)

5.2  函数占位参数

        语法:返回类型 函数名(数据类型){}  //(括号里只写数据类型,传递的参数类型必须和所写的一样)

void test1(int a, int)
{
	cout << "func" << endl;

}
void test2(int a, int =10)//占位参数可以有默认参数
{
	cout << "func" << endl;

}

5.3  函数重载

        作用:函数名可以相同,提高复用性

        满足条件
               ①同一个作用域。(ex:都在全局作用域下)
               ②函数名称相同。
               ③参数类型不同/个数不同/顺序不同。

//在全局作用域
void test()
{
	cout << "调用test( )" << endl;
}
void test(int a) 
{
	cout << "调用test(int a)" << endl;
}
void test(double a)
{
	cout << "调用test(double a)" << endl;
}
void test(int a, int b)
{
	cout << "调用test(int a, int b)" << endl;
}
void test(int a, double b)
{
	cout << "调用test(int a, double b)" << endl;
}
void test(double a, int b)
{
	cout << "调用test(double a, int b)" << endl;
}
int main()
{
	test();
	test(10);
	test(3.14);
	test(10,3.14);
	test(3.14, 10);
	return 0;
}

        注意:函数的返回值不能作为函数重载的条件(返回值类型不同不行,有二义性)

        引用作为函数重载的条件

//引用作为重载条件
void test(int &a)
{
	cout << "调用test(int &a)" << endl;
}
void test(const int& b)
{
	cout << "调用test(const int& b)" << endl;
}
int main()
{
	int a = 10;
	const int b = 10;
	test(a);
	test(b);
    test(10); 
	return 0;
}

        函数重载碰到默认参数

//函数重载碰到默认参数
void test(int a,int b=10)
{
	cout << "调用test(int &a)" << endl;
}
void test(int a)
{
	cout << "调用test(const int& b)" << endl;
}
int main()
{
	test(10);//err,出现二义
	return 0;
}

六、类和对象

         c++面向对象三大特性:封装、继承、多态

6.1  封装

6.1.1  封装的意义

         1. 将属性和行为作为一个整体。(放在一个class里面)
         2. 将属性和行为加以权限控制。
              public公共权限:类内外都可以访问
              protected保护权限: 类外不可以访问
             

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值