C++学习——共勉(一)

43 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天

前言

花些时间,去学习自己想去探索的事情,满满星光路,共勉!

一:简单介绍

C++语言是一种编译式的、通用的并且对大小写敏感的编程语言,完全支持面向对象的开发模式。

二:基本的输入和输出

1:认识相关函数

在C语言中,标准的键盘输入和屏幕输出功能分别使用scanf()和printf()两个函数实现。在C++语言中。类库中提供了输入流类 istream 和输出流类 ostream。cin和cout分别是是 istream 类和 ostream 类的对象,用来实现用来实现基本的键盘输入和屏幕输出。

cin实现输入的一般格式:

cin>>变量1>>变量2>>....>>变量n;

cout实现输出的一半格式:

cout<<变量1<<变量2<<....<<变量n;

2:代码示例

    #include <iostream>
     
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    #include<string>
    using namespace std;//表示命名空间std,命名空间的作用是为了消除同名引起的歧义
    int main() {
    	int oneInt1,oneInt2;
    	char strArray[20];//用字符数组oneArry来表示字符串 
    	string str;//用String类的对象来表示字符串 
    	double oneDouble;
    	char oneChar='a';
    	cout<<"输入两个整型值,一个字符,一个字符串和一个浮点值,";//字符串(String)是由数字、字母、下划线组成的一串字符。一般记为 s=“a1a2···an”(n>=0)。它是编程语言中表示文本的数据类型。 
    //cout输出
    	cout<<"以空格、Tab键或者 <Enter>键分隔:"<<endl;
    	cin>>oneInt1>>oneInt2>>oneChar>>strArray>>oneDouble;//cin输入
    	str = strArray;
    	cout<<"输入的数据是:"<<endl;//endl的作用是换行 
    	cout<<"字符串是:\t\t"<<str<<endl//\t是制表符Tab 
    		<<"两个整型值分别是:\t"<<oneInt1<<"和\t"<<oneInt2<<endl
    		<<"字符是:\t\t"<<oneChar<<"\n"//"\n"的作用和endl的作用一样,表示换行 
    		<<"浮点值是:\t\t"<<oneDouble<<endl; 
    	 
    	return 0;
    }

3:运行结果

图片.png

4:注意事项

假如cin和cout包含的项过长时,可以将其写在多行中,可以在>>和<<分行,但>>和<<后买你只能跟一个项,不能多个项连用:

cout<<a,b,c;  //这种写法只能输出a的值

cout<<a<<b<<c;//正确写法

cout<<a+b+c;//由于<<后是一个表达式,所以可以看作是一个项目,正确。

三:头文件和命名空间

头文件,我们可以理解成在打仗时需要调用的各种武器。C语言中使用头文件保存程序中用到的声明,C++也是如此,当程序中使用cin和cout时必须在程序的最前面包含输入和输出的标准流iostram,每条#include指令仅包含一条头文件,如果需要多个文件头,就需要多条#string指令。

常用的头文件有以下一些

图片.png

除了使用系统提供的头文件外,还可以定义自己的文件头,并在程序中使用#include指令将其包含起来。使用尖括号括住系统提供的文件头,使用双引号括住自己定义的头文件。

使用关键字namespace把大量的有逻辑联系的程序实体组合在一个标识符下,C++标准程序库中的所有标识符都定义在一个名为std的命名空间中,当程序使用标准标准程序库中的标识符时,如果没有语句“using namespace std;”则cin和cout都没有定义,string和endl也是如此

定义一个命名空间(名字空间)的语法格式:

namespace 命名空间名

{

        命名空间内的各种声明(函数声明、类声明、...)

}

引用其他命名空间的标识符的语法

命名空间名::标识符名

C++提供的using语句可以简化以上写法

using 命名空间::标识符;//可以在本文件中直接使用该标识符

using namespace 命名空间名;//可以在本文件中直接是使用指定命名空间的所有标识符

四:强制类型转换运算符

当不同的类型的变量进行混合运算的时候,系统会进行合理的类型转换,我们也可以使用强制类型转化运算符 static_cast(用于将一种数据类型转换成另一种数据类型) 或者 const_cast (用于去除指针和引用的常量性,但是不能去掉变量的常量性)进行转换。

static_cast <类型名> (表达式)

const_cast <类型名> (表达式)

1:代码示例

#include <iostream>
using namespace std; 
int main() {
	int a=10;
	const int*p =&a;//不能使用常量指针p来修改a的值
	const int ca = 30;//被const修饰
	int *q;
	cout<<"a的地址是:\t"<<&a<<"\ta的值是:\t"<<a<<endl;
	cout<<"*p指向的地址是:"<<p<<"\t*p的值是:\t"<<*p<<endl;
	q =const_cast<int*>(p);//去除p的常量性,赋值给q int型
	*q=20;
	cout<<"a的地址是:\t"<<&a<<"\ta的值是:\t"<<a<<endl;
	cout<<"*p指向的地址是:"<<p<<"\t*p的值是:\t" <<*p<<endl;
	cout<<"*q指向的地址是:"<<q<<"\t*q的值是:\t" <<*p<<endl;
	cout<<"分界线"<<endl;
	p=&ca;//ca的值不能被修改
	q=const_cast<int*>(p);
	*q=40;
	cout<<"ca的地址是:\t"<<&ca<<"\tca的值是:\t"<<ca<<endl;
	cout<<"*p指向的地址是:"<<p<<"\t*p的值是:\t"<<*p<<endl;
	cout<<"*q指向的地址是:"<<q<<"\t*q的值是:\t"<<*q<<endl; 
	return 0;
}

在这一个程序中,我们定义了一个常量型的p,和一个非常量的指针q。如果直接将p的值直接赋值给q,编译出来会出现错误,但是当我们使用强制性类型转换的话就会成功。

图片.png

2:程序解释

又发现分界线前后的p和q的地址相同,但是出现了值不相同的情况:当我们用同样的方法处理ca的时候,ca有了const属性,因此ca的值不会发生改变。即使我们将ca的指针p的const属性去掉然后重新赋值给q,再对q的值进行修改,并将所指的内容进行更改,还是不会对ca的值进行修改。因此就出现了变量ca的地址和指针q指向的地址相同但是值不同的情况。

五:函数参数的默认值

在C++语言中,可以在声明函数时为形参指定默认值,当我们在调用有默认参数值的函数时调用语句中可以不给出对应的实参,这就相当于调用该函数的默认值作为参数。指定默认值时不仅可以用常熟,还可以用任意有定义的表达式作为参数的默认值,但不允许是函数的局部变量。注意要先定义再声明最后再调用。 代码示例

#include <iostream>
 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
void func(int a=11,int b=12, int c=33) //为参数a,b,c分别设置默认值
{
	cout<<"a="<<a<<",b="<<b<<",c="<<c<<endl;
 } 
int main(int argc, char** argv)
{
	func();//调用时缺少了三个实参,就是用定义的参数的默认值,也就是无返回值 
	func(13);//调用时缺少后面的两个实参,就调用后买你凉饿参数定义的默认值
	func(13,14);//调用时缺少最后一个实参,最后一个就使用被定义中的默认值
	func(13,14,666); //三个参数均可调用实参,就不会使用定义中的默认值 
	return 0;

图片.png

1:注意事项

C++语言中规定:提供默认值时并且在函数声明时,必须按照从右至左的顺序提供,有默认值的形参必须在形参列表的最后。可以理解为,在有默认值的形参右侧,不能有无默认值的形参。

声明函数时,形参的最大默认值是从右至左

调用函数时,实参与形参是从左至右进行匹配对应的

2:简单举例

void defaultvalue1(int = 2double = 3.0);//对函数进行声明,正确。
 
void defaultvalue2 (int a,double = 3.0);//b有形参,并且在b的右侧没有出现没有默认值的形参,正确。
 
void defaultvalue3(int a = 2double b);//错误,a有形参,但是在a的右侧忽略了b的默认值。
 
 
假设给出如下函数声明:
void func(int a,int b=2,int c=3);
则:
func(12233);//正确
func();//错误,a没有声明默认值,必须给出实参值
func(1020);//正确,参数c没有给定实参值,因此调用默认值3
func(5,,8);//错误,从左至右给定实参值不能间断
 
假设给出如下的函数和变量声明:
int Max(int m,int n);
int a,b;
void func2(int x,int y = Max(a,b),int z = a-b)
{.....
}
则下列函数:
func2(4);//正确
func2(46);//正确
 
函数参数的默认值可以写在声明函数的地方,也可以写在定义函数的地方,但是不能两个地方都写。

六:引用和函数参数的传递

1:什么是引用

引用就好比是我们给变量起的一个别名。变量对应于某个内存地址,如果我们给变量起一个别名,就相当于变量和引用均对应到同一个内存地址。

类型名 &引用名 = 同类型的某变量名

int oneInt;//定义一个整型变量

int &name1 = oneInt;//name1就是一个引用,就是oneInt的别名,它的类型是int &型。

当我们声明引用后,系统并不为name1分配空间,name1和oneInt对应的是同一个地址,于是可以相互赋值。

当我们在引用时,变量已经进行初始化。系统会自动将变量初始化为0,不能出现空引用或者是声明引用的引用。引用名必须是一个合法的标识符。在定义引用的时候需要进行初始化。同一个变量的引用可以有多个。

2:常引用和普通引用

int oneInt;

const int &name1=oneInt;//定义了name1,它的类型是const int &。

 常引用和普通引用的区别:

常引用:不能修改引用的变量值。

普通引用:可以修改引用的变量值。

代码示例

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char** argv) 
{
	int oneInt = 1;//定义一个整型变量
	int & ref = oneInt;//普通引用  ref是oneInt的引用,是int & 类型
	const int & refc =oneInt;// 常饮引用 refc是oneInt的普通引用 
	ref=2;//修改ref的值,此时ontInt的值也被修改为2 
	cout<<"ontInt="<<oneInt<<","<<"ref="<<ref<<endl; 
	cout<<"refc="<<refc<<endl;//refc输出的是2,oneInt被普通引用做出了修改
	oneInt=3;//ref被修改为3 
	cout<<"ref="<<ref<<endl;
	cout<<"refc="<<refc<<endl;//ref和refc均输出为3
	int & refd = ref;//refd是ref的的引用,属于引用的引用,refd和ref都是oneInt的引用 
	cout<<"refd="<<refd<<endl;
  /*refc=4;
	cout<<"refc="<<refc<<endl; 
	ref是常引用,不能对引用的变量值进行修改 
  */
	return 0;
}

图片.png

3:传值和传引用

 在程序中不仅可以定义变量的引用,还可以用在函数中。

在C++中,函数调用时参数的传递方式有两种:传值和传引用

传值:本质上就是传递对象的值。

如果函数的形参不是引用,那么在调用时实参传递给形参的就是传值的方式,就是将实参的值拷贝给形参。在函数执行过程中均对该拷贝进行,函数执行完毕返回后,形参的值并不会拷贝会实参,也就是函数内部的形参不会影响到函数外部的形参。(当我们在进行传值时,将实参的值拷贝到栈中对应的形参的地址中,函数内部对形参的操作就是对这个地址的操作,而不是对实参所占用的地址进行操作的)

传引用:传递对象的首地址值。

如果函数的形参是引用,那么就采用传引用的调用方式。在传递的时候,形参对象名就相当于实参对象名的一个别名,两者等价,相当与传同一个地址,可以理解为是传地址。

代码示例

    #include <iostream>
    using namespace std;
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    void SwapValue(int a,int b)
    {
    	int tmp;
    	tmp = a;
    	a=b;
    	b =tmp;
    	cout<<"使用SwapValue中 a="<<a<<", b="<<b<<endl; //传值过程中,两个值在函数内部进行互换 
    }
    void SwapAddress(int& a,int& b)
    {
    	int tmp;
    	tmp = a;
    	a=b;
    	b = tmp;
    	cout<<"使用SwapAddress中 a="<<a<<", b="<<b<<endl; //传引用过程中,对形参进行引用,就相当于对a,b实参进行操作,因此在调用过程中和调用结束,值都会发生交换。 
    }
    int main(int argc, char** argv) {
    	int a=10,b=100;
    	cout<<"数据交换前 a="<<a<<",b="<<b<<endl;
    	SwapValue(a,b);
    	cout<<"调用SwapValue后 a="<<a<<", b="<< b<<endl;//传值结束后,实际上交换的是形参所在的内存地址中的内容,原来实参所在的地址并没有发生改变,因此函数调用结束后,值恢复。
    	a=10,b=100;
    	SwapAddress(a,b);
    	cout<<"调用SwapAddress后 a="<<a<<",b="<<b<<endl; //传引用结束后,a,b两值发生交换成功。 
    	return 0;
    }

图片.png

引用运用到函数中, 既可以当作函数的参数,也可以作为函数的返回值。

数据类型 & 函数名(参数列表);

代码举例

#include <iostream>
using namespace std;
int oneX = 10;
int oneY =100;
int & refValue(int & x) 
{
	return x;
}
int main()
{
	refValue(oneX)=20;//返回值是引用  
	cout<<"oneX="<<oneX<<endl;//输出20 
	refValue(oneY)= 200;
	cout<<"oneY="<<oneY<<endl;//输出200 
	
}