C++是在C的基础上发展起来并完全兼容C的,C++也可以理解为C的进化版,是C语言全方面的提升。笔者身为C++的初学者,仅是短时间的学习,仍是对C++这门语言的设计感到无比惊叹,更感慨其设计者,C++之父——Bjarne Stroustrup的才华。
在编写程序时,变量、函数和类的名称将都存在于全局作用域当中,可能会产生名称冲突、命名空间污染等问题。C++针对这种问题引入了namespace关键字。
命名空间:
namespace,
#include <iostream>
using namespace std;
namespace N1
{ int a=5;
int b=10;
int Add(int a,int b)
{
return a+b;
}
}
namespace N2
{
int a=2;
int b=3;
int Addplus(int a,int b)
{
return 2*(a+b);
}
}
namespace N1
{
int c=20;
}
int main()
{
N1::a=100;//作用域限定符访问命名空间内成员,对N1命名空间中a重新赋值
N2::a=200;//对N2命名空间中a重新赋值
N1::c=300;//编译器会合并相同命名空间
cout<<N1::Add(10,20)<<endl;// 30
cout<<N2::Add(10,20)<<endl;// 60
using namespace N1;//表示从这里往后使用N1命名空间,相当于将N1在这里展开
cout<<a<<endl;// 100
}
使用关键字namespace+命名空间的名字+{}
命名空间的使用:
命名空间的名字+::(作用域限定符)+成员名字
using+命名空间+::(作用域限定符)+成员名字,可以将成员引入
using namesapce + 命名空间,之后通过using命名空间+::(作用域限定符)来使用
命名空间可以嵌套,可以存在同名命名空间,编译器最后会把同名的命名空间合并成一个。
C++中的输入输出:
C++标准输入输出函数:#include<iostream>
using namespace std; //使用std命名空间,std是在<iostream>中的命名空间
cin>> cin表示标准输入(键盘)
cout<< <<endl; cout表示标准输出(控制台) endl是换行
#include<iostream> using namespace std;//要使用iostream中的std命名空间 //cin、cout和endl都是std命名空间中的成员
int main()
{
int a, b, c;
cin >> a >> b >> c;//可以同时多个输入,用空格隔开
cout << a<<" " << b <<" " << c <<" " << endl;//输出字符用""和'',endl表示换行
cout << a<<'\t' << b << '\t' << c <<'\t' << endl;
}
相较C,C++的输入输出用起来实在是舒服很多。
C++中的函数:
函数中的参数检查相对于C会更加的严格,(类型,个数,作用域),同时增加了缺省参数
缺省参数:即函数在声明定义时,可以先给参数赋一个默认值,在进行函数调用时,如果传参没有传递该参数,则会使用该默认值作为参数
缺省参数分类:
全缺省参数:即函数的所有参数都有一个默认值
半缺省参数:即部分参数有默认值
注:1. 半缺省参数必须从右往左依次来给出,不能间隔着给
2、缺省参数不能在声明和定义的时候同时出现
void TestFunc(int a = 10, int b = 20, int c = 30)//全缺省
{
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
void TestFunc1(int a, int b = 10, int c = 20)//半缺省
{
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
void test(int a = 10) {};//声明和定义时同时给出会报错,值一样也不行
void test(int a = 10)
{
cout << "hello rainbow" << endl;
}
函数重载:
函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,三者必须至少有一个不同。
重载原理:函数在编译时,经过预处理和编译阶段后,在内存中有了自己的内存空间,在汇编链接阶段,需要将函数从所在空间调用出来,这个调用是通过编译后的函数名来查找函数位置的,在C语言中,编译后的函数名相比于原来的函数名仅仅只增加了一个下划线_做修饰符,而在C++中,会根据函数的参数列表来形成一个修饰符修饰函数,所以只要函数的参数列表不同,最后生成的函数名也就不同,就可以实现同名函数的重载。
#include<iostream>
using namespace std;
//函数重载是指允许存在相同名称的函数,但是前提是这几个函数在同一个作用域中
//且这些函数的形参列表得不同,形参列表的不同又包括:参数的个数,参数的类型,参数的次序
// 与返回值的类型无关
//C与其它函数参数个数不同,D与E的参数次序不同,A与B类型不同
int Add(int a, int b) //A
{
return a + b;
}
/*double Add(int a, int b)//这就会和A无法重载,会报错
{
return a + b;
}*/
double Add(double a, double b)//B
{
return a + b;
}
int Add(int a, int b, int c)//C
{
return a + b + c;
}
//int Add(int a, double b)//D 把D和E注释掉
//{
// return a + b;
//}
//int Add(int b, double a)//E
//{
// return a + b;
//}
int main()
{
Add(1, 2.3);//给出两个参数,一个是整型,一个浮点型,编译器在编译时
//会对传递的实参类型进行推演,然后根据推演的结果选择合适的函数进行调用
//如果有合适的函数,合适的意思为参数的类型完全匹配,则直接调用
//如果没有完全匹配的参数类型,编译器则会尝试进行隐式类型转换
//转换后如果有合适的函数则调用,如果转换后存在多个函数均可匹配
//这时编译器就会报错,因为都合适不知道用哪个
//这里Add(1,2.3)经过隐式类型转换,既可以转换成A,也可以转换成B,所以会报错
}
引用:
相较C里的指针,C++中的引用实在是太友好了。
引用的概念:引用就是一个别名,编译器不会为引用变量开辟新的内存空间,引用变量与其引用的实体共用同一份内存空间,这么说是为了方便对于引用的理解,引用实际上是有开辟空间的,引用在代码层面就是实体的一个别名,在底层仍需要像指针一样解引用,引用的底层实现:就是按照指针的方式实现的,在底层:引用就是指针。
引用使用“&”符号定义变量
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int& ra = a;//ra即为a,是一个变量,只不过名称不同
cout << a<<" "<< ra << endl;
}
short a = 10;
int& ra = a;//报错
注意:引用的类型必须和引用实体是同一个类型
引用的特性:
1、引用在定义式必须初始化,指针没有要求
2、一个变量可以有多个引用,可以理解为一个人有多个别称
2、引用在初始化时引用了一个实体后,不能再引用其他实体
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int b = 10;
//int& ra;没有赋初值,报错
int& ra = a;
//int& ra = b;ra重定义,报错
int& rra = a;
cout << a<<" "<< ra <<" "<<rra << endl;
}
常引用:对于常量的引用需使用常引用,即用const + 引用,常量包括const修饰的变量以及自然常量。
#include<iostream>
using namespace std;
int main()
{
int a = 10;
const int& b = 20;//通过常引用给把常量赋给变量
const int& ra = a;
//ra = 20;const修饰ra使得ra不可修改
cout << b << endl;
a = 20;//直接给a变量重新赋值修改
}
引用的应用场景:
//1、传参
#include<iostream>
using namespace std;
void Swap(int& left, int& right)
{
int tmp;
tmp = left;
left = right;
right = tmp;
}
int main()
{
int a = 10;
int b = 20;
cout << a <<" "<<b << endl;
Swap(a, b);
cout << a <<" "<< b << endl;
}
//2、函数返回值
#include<iostream>
using namespace std;
int& Add(int a, int b) {
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
int sum = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;//7
//如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已
//经还给系统了,则必须使用传值返回。
cout << "Add(1, 2) is :" << sum << endl;//3
return 0;
}
引用和指针的不同点:
1、引用使用时必须初始化,指针则不用
2、引用初始化引用一个实体后不能再引用其他实体,指针可以在任何时候指向任意一个其他同类型的实体
3、指针有空指针NULL,引用没有空引用,必须初始化
4、sizeof含义不同,对于指针来说,sizeof一个指针,在32平台下都是四个字节,64位则是八个字节,而对于引用,是引用类型的大小
5、+1的含义不同,对于指针,指针+1是向后移动一个类型的大小,对于引用,+1就是引用的实体+1
6、有多级指针,没有多级引用
7、访问实体的方式不同,指针需要显式解引用,引用则是编译器自己处理
8、引用比指针更加安全
内联函数:
用关键字inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。
2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。