学习目标:
掌握C++这门语言面向对象的逻辑,能读懂代码,能实现简单的编写,运用。
在此记录一下学习过程。
*
学习内容:
————————1.引用————————
第一个部分讲了引用的概念,定义的&r就是n变量,改变n就会改变r。
下面的写法定义了一个引用,并将其初始化为引用某个变量。
类型名 & 引用名 = 某变量名;
int n = 4;
int & r = n; // r引用了 n, r的类型是 int &
某个变量的引用,等价于这个变量,相当于该变量的一个别名。
int n =7;
int &r = n;
r = 4;
cout << r; //输出 4
cout << n; //输出 4
n=5;
cout<< r; //输出 5
注意
一、定义引用时一定要初始化成引用某个变量
二、初始化后,他就一直引用该变量,不会再引用别的变量
三、引用只能引用变量,不能引用常量和表达式
#include<bits/stdc++.h>
using namespace std;
int main(){
double a =4,b=5;
double & r1 =a;
double & r2 =r1; // r2也引用a
r2=10;
cout << a<<endl; //输出10
r1 = b; //引用是从一而终的,这里是赋值
cout << a<<endl; //输出5
}
如何编写交换两个整型变量值得函数?
有了引用的概念,这样程序就看起来简洁的多了。
#include<bits/stdc++.h>
using namespace std;
void swap(int & a,int & b)
{
int tmp;
tmp =a ;a=b ;b=tmp;
}
int main(){
int n1=5;
int n2=8;
swap(n1,n2);
cout<<n1<<endl; //8
cout<<n2<<endl; //5
}
如果是使用c语言的话,就需要传入n1n2的地址了,如下所示:
void swap(int * a,int * b)
{
int tmp;
tmp =a ;a=b ;b=tmp;
}
int main(){
int n1=5;
int n2=8;
swap(&n1,&n2);
}
所以C++里引用的概念还是比较好用的。
**
引用也可以作为函数的返回值:
**
#include<bits/stdc++.h>
using namespace std;
int n=4;
int & SetVlue()
{
return n;
}
int main(){
SetVlue()=40;
cout << n;
return 0;
}
虽然还不知道有什么用,但是后面有可能能用的到。
**
常引用:
**
定义引用时,前面加const关键字,即为“常引用”
int n;
const int & r = n;
//r的类型是const int &
常引用的特点就是:不能通过常引用取修改其引用的内容
int n =100;
const int & r =n;
r=200;//编译出错
n=300;//编译没问题
————————2.常量————————
1)定义常量
const int MAX_VAL =23;//整型常量
const double Pi =3.14;//浮点型常量
const char * SCHOOL_NAME = "Peking University"//字符串指针的常量
建议多用const 少用define,因为const是有类型的,便于以后类型的检查。
2)定义常量指针
不可通过常量指针修改其指向的内容
int n,m;
const int *p = & n;
*p = 5;//编译会出错
n =4;//可以被修改
p = &m;//也可以再指向别的地方
不能把常量指针赋值给非常量指针,反过来可以
const int *p1;int *p2;
p1=p2;//ok
p2=p1;//error
p2=(int *)pi;//ok,强制类型转换
函数参数为常量指针时,可避免函数内部不小心改变参数指针所指地方的内容。
void MyPrintf(const char * P)
{
strcpy(p,"this");//编译出错
printf("%s",p);//ok
}
因为strcpy会修改p指向的内容,但是printf是仅仅将p指向的内容打印出来,这就是常量指针作为函数参数时候的用法。
3)定义常引用
不能通过常引用修改其引用的变量
上一节说过了。
————————3.动态内存分配————————
用new 运算符实现动态内存分配
第一种用法,分配一个变量
P=new T;
T是任意类型名,P是类型为T * 的指针。
动态分配出一片大小为 sizeof(T)字节的内存空间,并且将该内存空间的起始地址赋值给P。
比如:
#include<bits/stdc++.h>
int main(){
int *pn;
pn = new int;//动态分配出一个int大小的存储空间,然后把这片存储空间赋值给指针pn
*pn =5;//就可以通过pn向这片空间写5
}
第二种用法,分配一个数组:
P=new T[N];
T :任意类型名
P :类型为T * 的指针
N :要分配的数组元素的个数,可以是整型表达式
动态分配出一片大小为 sizeof(T)*N字节的内存空间,并
且将该内存空间的起始地址赋值给P。
示例:
#include<bits/stdc++.h>
int main(){
int *pn;
int i =5;
pn = new int[i *20];
pn[0] =20;
pn[100]=30;//编译没问题。运行时导致数组越界
}
new 运算符的返回值类型
new T;
new T[n];
这两个表达式返回值的类型都是T*
!!!
用“new”动态分配的内存空间,一定要用
“delete”运算符进行释放
delete 指针;// 该指针必须指向new出来的空间
#include<bits/stdc++.h>
int main(){
int *p = new int;
*p = 5;
delete p;
delete p; //导致异常,一片空间不能delete多次
}
这只是delete一个动态分配出来的变量,如果用delete释放动态分配的数组,要加“[ ]”
delete [ ] 指针;//该指针必须指向new出来的数组
int * p = new int[20];
p[0]=1;
delete []p;//如果没有中括号,不会完全被回收
——————4.内联函数,函数重载,函数缺省参数——————
内联函数
函数调用是有时间开销的。如果函数本身只有几条语句,执行非常快,而且函数被反复执行很多次,相比之下调用函数所产生的这个开销就会显得比较大。
为了减少函数调用的开销,引入了内联函数机制。编译器处理对内联函数的调用语句时,是将整个函数的代码插入到调用语句处,而不会产生调用函数的语句。
在函数定义前面加“inline”关键字,就可以定义内联函数
例如:
inline int Max(int a,int b)
{
if(a>b) return a;
return b;
}
这样定义一个函数,就不会产生参数入栈等一系列的操作,会加速程序执行时间。
函数重载
一个或多个函数,名字相同,然而参数个数或参数类型不相同,这叫做函数的重载。
以下三个函数是重载关系:
int Max(double f1,double f2) { }
int Max(int n1,int n2) { }
int Max(int n1,int n2,int n3) { }
Max(3.4,2.5); //调用 (1)
Max(2,4); //调用 (2)
Max(1,2,3); //调用 (3)
Max(3,2.4); //error,二义性
函数重载使得函数命名变得简单。
编译器根据调用语句的中的实参的个数和类型判断应该调用哪个函数。
函数的缺省参数
C++中,定义函数的时候可以让最右边的连续若干个参数有缺省值,那么调用函数的时候,若相应位置不写参数,参数就是缺省值。
void func( int x1, int x2 = 2, int x3 = 3)
{ }
func(10 ) ; //等效于 func(10,2,3)
func(10,8) ; //等效于 func(10,8,3)
func(10, , 8) ; //不行,只能最右边的连续若干个参数缺省
函数参数可缺省的目的在于提高程序的可扩充性。
即如果某个写好的函数要添加新的参数,而原先那些调用该函数的语句,未必需要使用新增的参数,那么为了避免对原先那些函数调用语句的修改,就可以使用缺省参数。
学习时间:
2021.3.18 周四 上午10.20 - 下午 15.08
学习产出:
把vscode的环境都配置好了,不知道为什么执行速度有点慢
然后又下了一个dev c++
比较小巧的一个编译器,不过没有自动补全有点难受,但是执行速度也很慢,可能是电脑的原因吧。。