在C/C++中,变量、函数以及类都是大量存在的,这些变量、函数和类的名称都将存在于全局作用域中,而它们的名称有可能一样或者和C/C++库中的一些名称相同,而这会导致很多冲突发生。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,而使用命名空间需要使用到namespace这一个关键字,即namespace的出现就是针对这种问题的。
#include
using namespace std;
int rand = 1;
int main()
{
cout << rand << endl;
因为C++标准库中有一个rand的函数,而rand是定义在全局的变量,标准库中的rand函数默认也是在全局展开的,而这两个东西的名字一样,编译器不知道要调用哪一个,所以就报错了。
定义命名空间,需要使用到namespace关键字,该关键字后面跟命名空间的名字,然后接一对{}即可,{}中的成员即为命名空间的成员,{}为这些成员的域。即一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。
#include
using namespace std;
namespace snow
{
int rand = 1;
int Add(int num1, int num2)
{
return num1 + num2;
}
struct Node
{
struct Node* next;
int val;
};
}
namespace snow
{
int rand = 1;
int Add(int num1, int num2)
{
return num1 + num2;
}
namespace dragon
{
int num3 = 10;
int num4 = 40;
}
}
//Test.h
namespace snow
{
int Mul(int x, int y)
{
return x * y;
}
}
#include
#include"Test.h"
using namespace std;
//命名空间
namespace snow
{
//int rand = 1; //将snow命名空间展开时,此语句最好注释掉
int Add(int num1, int num2)
{
return num1 + num2;
}
namespace dragon
{
int num3 = 10;
int num4 = 40;
}
}
using namespace snow;
using dragon::num4;
int main()
{
cout << Add(10, 20) << endl;
cout << dragon::num3 << endl;
cout << num4 << endl;
//上方展开后,下面那样写也没问题
cout << dragon::num4 << endl;
cout << Mul(10, 20) << endl;
return 0;
}
写程序少不了的就是输入与输出语句,像C语言中的输出函数printf与输入函数scanf。而在C++中则是使用cout与cin来进行输出与输入,比如一个简单的C++程序可以如下方那么写。
#include
using namespace std;
int main()
{
int x;
cin >> x;
cout << "Hello world!!!" <<e ndl;
return 0;
}
缺省参数是声明或定义函数时为函数的形参(形式参数)指定一个缺省值。在调用该函数时,如果没有传入实参则采用该函数形参的缺省值,否则使用传入的实参。
#include
using namespace std;
void Func(int a = 10)
{
cout << a << endl;
}
int main()
{
Func();
Func(20);
return 0;
}
void Func(int a = 10, int b = 20, int c = 30)
{
cout << a << " " << b << " " << c << endl;
}
int main()
{
Func();
Func(40);
Func(40, 50);
Func(40, 50, 60);
return 0;
}
void Func(int a, int b = 20, int c = 30)
{
cout << a << " " << b << " " << c << endl;
}
int main()
{
Func(40);
Func(40, 50);
Func(40, 50, 60);
return 0;
}
用inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开该函数的函数体,没有函数调用建立栈帧的开销,内联函数能够提高程序运行的效率。
将该函数用inline修饰后需要做一些操作才能看到inline修饰后的效果。
图中call为调用函数。
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的是一直没有人去使用它。而在C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。但需要注意的是使用auto定义变量时必须对其进行初始化,因为在编译阶段编译器需要根据初始化的表达式来推导auto的实际类型。
int Testauto()
{
return 20;
}
void Test1()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = Testauto();
//输出变量的类型
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
//auto e; //报错,需要对其进行初始化
}
void Test2()
{
int a = 10;
auto b = a;
auto* c = &a;
auto d = &a;
auto& e = a;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
cout << typeid(e).name() << endl;
}
void Test3()
{
auto a = 10, b = 20;
//auto c = 30, d = 40.4; //编译失败,因为两个变量的初始化表达式类型不同
}
当在同一行声明或者定义多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。下方为将注释展开时编译器报的错误。
#include
#include
#include
void Test5()
{
std::map<std::string, std::string> m;
std::map<std::string, std::string>::iterator it1 = m.begin();
auto it2 = m.begin();
}
void Test4()
{
int arr1[] = { 1,2,3,4 };
auto arr2[] = { 1,2,3,4 }; //不能直接用来声明数组
}
void Testauto2(auto x) //不能作为函数形参,因为无法对其进行推导
{}
我们在创建一个指针又不知道要将这个指针指向哪个对象时,在C语言我们会用NULL,但在C++中最好是使用nullptr。
#include
using namespace std;
void Func(int x)
{
cout << "Func(int x)" << endl;
}
void Func(int* x)
{
cout << "Func(int* x)" << endl;
}
int main()
{
Func(0);
Func(NULL);
Func((int*)NULL);
Func(nullptr);
return 0;
}
引用是给已经存在的变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共使用同一块内存空间。
void Test1()
{
int a = 10;
//int ra; //未初始化,编译时会出错
int& ra = a;
//double& rd = a;
cout << a << endl;
cout << ra << endl;
printf("&a = %p\n", &a);
printf("&ra = %p\n", &ra);
}
void Test2()
{
const int a = 10;
//int& ra = a; //出错,限定符const被丢弃了
const int& ra = a;
const int& b = 10;
cout << "a = " << a << endl;
cout << "ra = " << ra << endl;
cout << "b = " << b << endl;
double d = 20;
//int& c = d;
const int& c = d;
cout << "d = " << d << endl;
cout << "c = " << c << endl;
}
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
int& Add(int x, int y)
{
int z = x + y;
return z;
}
void TestAdd()
{
int x = 10, y = 20;
int& ret = Add(x, y);
cout << ret << endl;
cout << ret << endl;
Add(1, 2);
cout << ret << endl;
cout << ret << endl;
}
int& count()
{
static int n = 0;
++n;
return n;
}
在语法概念上引用就是一个别名,没有独立的空间,和其引用实体共用同一块空间。但在底层实现上却是有空间的,因为引用是按照指针的方式来实现的。
通过反汇编可以看到,引用和指针的操作是相同的。
函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数数量、类型、类型顺序中一个或多个)不同,常用来处理实现功能类似但数据类型不同的问题,减去了为多个功能类似的函数起名字的烦恼。
#include
using namespace std;
void Func()
{
cout << "Func()" << endl;
}
void Func(int x)
{
cout << "Func(int x)" << endl;
}
void Func(double x)
{
cout << "Func(double x)" << endl;
}
void Func(int x, double y)
{
cout << "Func(int x, double y)" << endl;
}
void Func(double y, int x)
{
cout << "Func(double y, int x)" << endl;
}
int main()
{
Func();
Func(30);
Func(50.5);
Func(40, 50.5);
Func(50.5, 40);
return 0;
}
由于Windows下的VS编译器修饰规则过于复杂,而Linux下g++编译器的修饰规则相对VS来说比较简单易懂,下面我们使用g++演示C++程序的重载函数被修饰后的函数名字,而C语言则是使用gcc编译器。
本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
创作不易,如果觉得博主写得不错,请务必点赞、收藏加关注