八十、 引用
80.1 概念
- 引用是给目标取了个别名。
- 引用与目标,它俩的地址一样
80.2 格式
- 数据类型 &引用名 = 同类型的变量名;
数据类型 &引用名 = 同类型的变量名; eg: int a; int &b = a; //b引用a,给a取个别名叫b
80.3 数组的引用
80.3.1 概念
- 给数组取个别名
80.3.2 实例
#include <iostream>
using namespace std;
int main()
{
int a[5] = {10,20,30,40,50};
//数组指针
int (*p)[5] = &a;
//数组引用
int (&b)[5] = a; //给a 数组取个别名叫b
cout << a[4] << endl;
b[4] = 9999; // ==> a[4] = 9999
cout << a[4] << endl;
return 0;
}
80.4 函数的引用
- 给函数取个别名
80.5 结构体中有引用成员
- 如果结构体中有引用成员,那么使用这样结构体类型定义变量时,必须初始化,否则报错。
80.6 实例
#include <iostream>
using namespace std;
//结构体中有引用
struct student{
int id;
string name;
float &socre;
};
int my_get_max(int a, int b){
return a > b ? a : b;
}
//函数重载
//参数列表不同,与返回值类型无关
double my_get_max(double a, double b){
return a > b ? a : b;
}
int main()
{
int arr[10] = {1, 2, 3};
//数组的引用
int (&aa)[10] = arr;
aa[1] = 0;
for(int i = 0; i < 3; i++)
cout << "aa[" << i << "] = " << aa[i] << endl;
//函数的引用
int (&get_max)(int , int) = my_get_max;
cout << get_max(10, 20) << endl;
//函数指针,调用重载的函数
double (*get_max_double)(double , double) = my_get_max;
cout << get_max_double(10.23, 20.12) << endl;
//结构体中有引用
//在声明时,必须初始化
float f = 101;
struct student s1 = {1, "lalal", f};
return 0;
}
80.7 传值、传址、传引用
- 传值 一定不会改变目标的值
- 传址 有可能改变目标的值 具体看代码设计
- 传引用 有可能改变目标的值 具体看代码设计
#include <iostream>
using namespace std;
void fun(int a, int b) // int a = a
{
a++;
b++;
}
void fun2(int *a, int *b) // int *a = &a
{
(*a)++;
(*b)++;
}
void fun3(int &x, int &y) // int &x = a
{
x++;
y++;
}
int main()
{
int a = 10, b= 20;
cout << "a = " << a << " b = " << b << endl;
fun(a, b); //传值 一定不会改变目标的值
cout << "a = " << a << " b = " << b << endl;
fun2(&a, &b); //传址 有可能改变目标的值 具体看代码设计
cout << "a = " << a << " b = " << b << endl;
fun3(a, b); //传引用 有可能改变目标的值 具体看代码设计
cout << "a = " << a << " b = " << b << endl;
return 0;
}
80.8 当引用作为函数返回值
- 当引用作为函数返回值,要求变量的生命周期要长。
- 静态局部变量
- malloc申请的堆区空间
#include <iostream>
using namespace std;
int &fun()
{
//int num = 10;局部变量不能最为函数的引用返回值
static int num = 10;
return num;
}
int main()
{
cout << fun() << endl;
int a = 12;
fun() = a;
cout << fun() << endl;
return 0;
}
总结:指针和引用区别 (面试重点)
回答方式:先回答指针与引用分别是啥,然后再回答区别
- 指针:指针是保存变量的地址的变量
- 引用:引用就是给变量取个别名
- 定义指针是需要占用空间,而引用不需要。
- 指针可以先定义后指向,而引用必须定义时初始化。
- 指针可以改变(目标)指向,而引用不可以。
- 指针有二级指针,而引用没有二级引用(没有引用的引用,原因:引用不是数据类型)
- 有指针数组,但没有引用数组(原因:引用不是数据类型)
八十一、 const
- 修饰变量,表示变量的值不能被修改。
int *p;
int const *p; //指向可变,指向里的值不可变
int * const p; //指向不可变,指向里的值可变
int const * const p; //都不可变
int a = 10;
int const b = 20; // ==> const int b = 20;
int *pa = &a; //可以
int *pb = &b; //不可以 不合法
int const *paa = &a;//可以
int const *pbb = &b;//可以 合法
int a = 10;
int const b = 20; // ==> const int b = 20;
int &aa = a; //可以
int &bb = b; //不可以 不合法
const int &bbb = b; //可以 合法
八十二、 函数重载
82.1 概念
- 在同一个作用域下,两个以上的函数,取相同的函数名,其参数个数或者类型不同,编译器会根据实参的个数或者类型自动调用哪一个函数,这就是函数重载。
#include <iostream>
using namespace std;
int fun()
{
return 10+10;
}
int fun(int x)
{
return x+10;
}
int fun(int x, int y)
{
return x+y;
}
int main()
{
int a = 10, b=20;
cout << fun() << endl;
cout << fun(23) << endl;
cout << fun(a,b) << endl;
return 0;
}
82.2 默认参数的函数定义和使用
- 实参为空时,按照形参的默认参数来
- 实参不为空时,按照实参来
void fun2(string name = "hello world") //默认参数
{
cout << name << endl;
}
int main()
{
fun2();
fun2("hello kitty");
return 0;
}
82.3 哑元(了解)
- 定义函数的时候,只定义形参类型,不定义形参名,在函数中也不使用该形参。
- 作用:没有作用,占位。
- 一般会发生在 :
- 假设原本函数的功能时三个数运算
- 现在需要换成俩数运算
- 那么就把不需要的那个数的位置,参数名不写
- 且函数功能中也更新成俩数运算的
- 这样使用 哑元 的方式迭代更新,避免了修改主调处代码(在大量调用该函数时就明白为啥了)
#include <iostream>
using namespace std;
//int fun(int m, int n, int k)
//{
// return m+n+k;
//}
int fun(int m, int, int k)
{
return m+k;
}
int main()
{
cout << fun(1,2,3) << endl;
cout << fun(1,2,3) << endl;
cout << fun(1,2,3) << endl;
cout << fun(1,2,3) << endl;
cout << fun(1,2,3) << endl;
return 0;
}
82.4 内联函数
- 要求:
- 函数体要小
- 不能有复杂的语句 比如循环、递归
- 一般代码不超过5行
- 目的:提高代码的运行效率,在编译的时候展开
- 关键字: inline
- 内联函数和带参宏替换的区别
- 内联函数是函数的调用,宏替换就是替换
- 内联函数是在编译时展开,宏替换在预处理的时展开
#include <iostream>
using namespace std;
#define MAX(m,n) m>n?m:n
inline int max(int m, int n) //内联函数
{
return m>n?m:n;
}
int main()
{
int m = 1;
int n = 1;
int c;
c = max(++m, n);
cout << "m = " << m << " n = " << n << " c = " << c << endl;
m = 1;
n = 1;
c = MAX(++m, n);
cout << "m = " << m << " n = " << n << " c = " << c << endl;
return 0;
}
八十三、 C++的结构体
83.1 C语言与C++结构体的区别
- C语言中结构体,在c++中依然适用。
- C++中的结构体中可以函数,C语言中不可以。
- C++中在定义结构体类型的时候,可以给变量初始值,C语言中不可以。
- C++中在使用结构体类型定义变量时,可以省略关键字struct不写,C语言中不可以。
- C++中的结构体中的成员有访问权限,C语言没有访问权限。
- C++中的结构体存在继承,C语言没有。
- C++中的结构体中有特殊的成员函数,C语言没有。
注意:结构名首字母大写、C++中的结构体的权限默认是共有的
权限 : 共有权限、 保护权限、 私有权限
public protected private
- 示例:
#include <iostream>
using namespace std;
struct Student
{
string name;
int id = 1001; //可以给定初始值
double score;
void show() //可以在结构体内部封装函数
{
cout << name << endl;
cout << id << endl;
}
};
int main()
{
Student s1; //可以省略关键字struct不写
s1.name = "zhangsan";
cout << s1.name << endl;
s1.show();
return 0;
}
八十四、 C++中的类
- C++中类是有C++中的结构体演变而来的,只是默认访问权限和默认继承方式以及关键字不同。
- 类的关键字:class
- 默认访问权限是私有的。
84.1 格式(语法)
class 类名
{
public:
公共的数据成员、成员函数
protected:
受保护的数据成员、成员函数
private:
私有的数据成员、成员函数
};
84.2 访问权限介绍
- public:
该权限是公共权限,表示该权限下的属性(变量)、方法(函数),可以在类内、子类、类外被访问。
- protected:
该权限是保护权限,表示该权限下的属性(变量)、方法(函数),可以在类内、子类可以被访问,类外不可以被访问。
- private:
该权限是私有权限,表示该权限下的属性(变量)、方法(函数),只可以类内被访问,子类和类外不可以被访问。
- 一般数据成员权限是私有的private, 成员函数是共有的public ,
- 成员函数一般是作为接口,供外界使用的。
- 具体还是要看代码设计。
- 相关名称:
- 类里有成员组成,
- 成员 :数据成员、成员函数
#include <iostream>
using namespace std;
//属性---变量
//方法---函数
//封装 ---- 属性+方法
class Student //封装了一个学生这样的 类
{
private:
string name;
protected:
int id;
public:
double score;
public:
void show()
{
cout << name << endl; //类内的成员函数,可以访问私有数据成员
cout << id << endl; //类内的成员函数,可以访问保护数据成员
cout << score << endl; //类内的成员函数,可以访问共有数据成员
}
void init(string n, int i)
{
name = n;
id = i;
}
};
int main()
{
Student s1; //用学生这样的类 实例了一个 对象
s1.score = 99; //共有权限下的成员,可以在类外被访问
//s1.id = 1001; //保护权限下的成员,不可以在类外被访问
//s1.name = "zhangsan"; //私有权限下的成员,不可以在类外被访问
s1.init("张三",1001);
s1.show();
return 0;
}
84.3 封装
- 类的三大属性:封装、继承、多态
封装:把数据和对数据的处理捆绑在一起的过程,就叫封装 (属性(变量)+方法(函数))
84.4 成员函数中的形参和数据成员同名
- 表明数据成员是 哪个类的 类名 加 作用域限定符
- 在每个类里的成员函数(非静态成员函数)都一个隐藏的this指针。
- this指针,谁使用我,我就指向谁。
#include <iostream>
using namespace std;
class Student
{
private:
string name;
int id;
public:
void init(string name, int id)
{
// Student::name = name;
// Student::id = id;
this->name = name;
this->id = id;
}
void show()
{
cout << "name = " << name << endl;
cout << "id = " << id << endl;
}
};
int main()
{
Student stu1;
stu1.init("张三",1001);
stu1.show();
return 0;
}
84.5 this指针
- this指针是所有非静态成员函数里的隐藏的一个形参
- this指针对像本身,谁使用我,我就指向谁。
- this指针的原型,eg:
Student * const this;
- 示例 :
#include <iostream>
using namespace std;
class Student {
private:
int id;
protected:
string name;
public:
double score;
void init(int id, string name){
this->id = id;
this->name = name;
}
void show(){
cout << "id = " << this->id << endl;
cout << "name = " << this->name << endl;
cout << "score = " << this->score << endl;
};
int main()
{
Student s1;
s1.init(1010, "法外狂徒");
s1.score = 66.6;
s1.show();
return 0;
}
84.6 类外定义成员函数
- 在类内声明函数
- 在类外进行函数实现 表明属于哪个类的,需要加上类名和作用域限定符
- eg: 函数返回类型 类名::函数名(形参列表)
#include <iostream>
using namespace std;
class Student {
private:
int id;
protected:
string name;
public:
double score;
void show();
void init(int id, string name);
};
void Student::init(int id, string name){
this->id = id;
this->name = name;
}
void Student::show(){
cout << "id = " << this->id << endl;
cout << "name = " << this->name << endl;
cout << "score = " << this->score << endl;
}
int main()
{
Student s1;
s1.init(1010, "法外狂徒");
s1.score = 66.6;
s1.show();
return 0;
}
小作业 :
自己封装一个矩形类(Rect)
且多文件编译
拥有私有属性:
宽度(width)、高度(height)
定义公有成员函数:
初始化函数:void init(int w, int h)
更改宽度的函数:set_w(int w)
更改高度的函数:set_h(int h)
输出该矩形的周长和面积函数:void show()
我写的:
main.cpp
#include "rect.h"
int main(){
Rect rec;
rec.init(2, 3);
rec.show();
rec.set_w(4);
rec.show();
rec.set_h(5);
rec.show();
return 0;
}
rect.h
#ifndef __RECT_H__
#define __RECT_H__
#include <iostream>
class Rect {
private:
// 宽度
double width;
// 高度
double height;
public:
void init(double w, double h);
void set_w(double w);
void set_h(double h);
void show();
};
#endif
rect.cpp
#include "rect.h"
using namespace std;
void Rect::init(double w, double h){
this->width = w;
this->height = h;
}
void Rect::set_w(double w){
this->width = w;
}
void Rect::set_h(double h){
this->height = h;
}
void Rect::show(){
cout << "宽 = " << this->width << " 高 = " << this->height << endl;
cout << "此矩形周长为 : " << 2 * (this->width + this->height) << endl;
cout << "此矩形面积为 : " << this->width * this->height << endl << endl;
}
makefile
EXE=Rect
CC=g++
CFLAGs=-c
OBJs+=main.o
OBJs+=rect.o
all:$(EXE)
$(EXE):$(OBJs)
$(CC) $^ -o $@
%.o:%.c
$(CC) $(CFLAGs) $^ -o $@
clean:
rm *.o $(EXE)