赞
踩
namespace + 命名空间的名字 + {}
。其中 { } 内容即为命名空间的成员,注意最后的右花括号后不用加分号结尾。
// 定义命名空间N1 namespace N1 { int a = 10; int b = 20; int Add(int left, int right) { return left + right; } // 嵌套在 N1 中的命名空间 N2 namespace N2 { int a = 30; int d = 40; int Sub(int left, int right) { return left - right; } } }
一个命名空间就定义了一个新的归属,命名空间中的所有内容都局包含于该命名空间中。内部可以直接使用,外部使用时必须指定它属于是哪个命名空间。
方法一:通过域限定符(::)直接访问命名空间中的成员
int main()
{
printf("%d\n", N1::a); // 10
printf("%d\n", N1::N2::a); // 30
return 0;
}
方法二:使用 using 将命名空间中的成员单独引入,后面使用这个成员时,就可以可以不指定它来自于那个命名空间中了
using N1::a;
int main()
{
// a被引入了可以直接使用
printf("%d\n", a); // 10
return 0;
}
方法三:使用 using namespace 将整个命名空间引入
using namespce N1;
int main()
{
// 命名空间 N1 中的a和b都可以直接使用了
printf("%d\n", a); // 10
printf("%d\n", b); // 20
return 0;
}
工程项目中:可能会产生命名冲突,所以把常用库里面一些对象或者类型展出来。比如:using std::cin、using std::cout 等。
日常练习中:不在乎跟库命名冲突,所以可以把库的命名空间全部展开,比如:using namespace std;
cin : 标准输入(键盘)
cout : 标准输出(控制台)
#include<iostream>
// 把 std 全部展开
// using namespace std;
// 单独展开 std 命名空间里面的 cin 和 cout
using::std::cin;
using::std::cout;
int main()
{
int a;
cin >> a; //输入
cout << a; //输出
return 0;
}
缺省参数是在定义或声明函数时为函数的参数指定一个默认值。这样在调用该函数时,如果没有传对应的实参则该参数的值就使用之前设定好的默认值(缺省值)。
// TestFunc 函数有一个缺省参数
void TestFunc(int a = 0)
{
cout<<a<<endl;
}
int main()
{
// 没有传参时,使用参数的缺省值
TestFunc();
// 传参时,使用指定的实参
TestFunc(10);
}
1、全缺省(形参全部给定缺省)
void TestFunc(int a = 10, int b = 20, int c = 30)
{
cout<<"a = "<<a<<endl;
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
}
//------输出结果------
a = 10
b = 20
c = 30
2、半缺省参数(形参从右往左连续缺省)
void TestFunc(int a, int b, int c = 30) { cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl; } int main() { TestFunc(88, 99); return 0; } //------输出结果------ a = 88 b = 99 c = 30
补充:C++中的缺省函数有哪些?
C++ 中允许同时定义多个函数名相同,但参数列表不同的多个函数,常用来实现功能类似但数据类型不同的问题。
参数列表不同指的是参数列表中,参数的类型、顺序、个数不同
在 Linux 中:经 gcc 修饰后的函数其名字不变,而经 g++ 修饰后的函数,其名字变成 _Z + 函数名长度 + 函数名 + 参数类型首字母
,即 g++ 编译器将函数参数类型的信息也给添加到了修饰后的函数名中。
综上分析,C语言之所以没办法支持函数重载,因为同名函数没办法被区分开。而 C++ 中只要是函数的参数类列表不同,即使是同一个名称的函数,它被 g++ 编译器修饰后的名称依然可以把它们区分开,这样就实现了函数重载。
① 函数是否构成重载与形参变量的名字相同与否无关,只和形参的类型有关:
// 不构成重载,因为函数名经过编译器修饰后还是一样的
void func(int i, int j) //_Z4funcii
{}
void func(int a, int b) //_Z4funcii
{}
② 函数是否构成重载与返回值类型无关:
// 返回值类型都为 int
// 下面两个函数不构成函数重载
int Add(int i, int j) // _Z3Addii
{}
// 返回值类型为double
double Add(int i, int j) // _Z3Addii
{}
③ 涉及到缺省参数时可能会发生调用不明确的问题:
void func(int a)
{}
void func(int a,int b=10)
{}
int main()
{
// error:不明确到底是调用带缺省的还是不带缺省的
func(10);
}
C++ 可以使用自己的那套函数名修饰规则来支持函数重载。因为 C++ 兼容 C语言,所以它也可以支持 C语言 的那套函数名修饰规则(就是直接以函数名来区分函数);但反过来 C语言 不支持 C++ 的那套函数名修饰规则。
场景:当我们用 C++ 写出几个函数接口卖给客户时,为了满足更多客户的需求(要求不仅 C++ 能调用,C语言 也要能用),我们干脆统一用 C语言 的那套函数名修饰规则来处理这个函数接口,在函数声明处加上 extern “C” 即可。
比如:tcmalloc 是 google 用 C++ 实现的一个项目。他提供 tcmallc() 和 tcfree() 两个接口。但如果是 .C 项目就没办法使用这套接口,可以在函数声明前加上 extern “C” 来解决。
给已存在变量取一个别名,编译器不会为该引用变量开辟内存空间,它和被引用的变量共用同一块内存空间。
使用规则: 类型& 引用变量名 = 引用实体;
int main()
{
int a = 10;
int& ra = a;// ra 引用 a
//a和ra地址相同
printf("%p\n", &a);
printf("%p\n", &ra);
return 0;
}
int main()
{
// 1.该语句编译时会出错,原变量a被const修饰权限为只读,而引用对象的访问权限是可读可写的,权限增大了(不允许)
const int a = 10;
int& ra = a;
// 2.正常编译,b可读可写,b1权限为只读,权限缩小;至于b2,权限为可读可写,也是可以的
int b = 10;
const int& b1 = b;
int& b2 = b;
return 0;
}
int main()
{
// 可以通过,只是单纯的传值,不涉及权限的缩小和放大
const int a = 10;
int b = a;
return 0;
}
涉及到隐式类型转换,都是右值产生一个中间变量先进行值传递,然后中间变量在和左值进行相应操作的。在进行强制类型转换和函数调用后值返回时也会产生临时变量,临时变量都具有常性。
//类似于C语言传地址,不过减少了对地址的解引用操作,可以直接修改外面的对象
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
//传引用返回 int& Count() { static int n = 0; n++; //返回n本身 return n; } //传值返回 int Count() { static int n = 0; n++; //返回n的值的一份临时拷贝对象 return n; }
语法概念上引用就是一个别名,和其引用实体共用同一块空间;而指针就是一个存放地址的变量。在底层实现上,引用是按照指针方式来实现(指针访问对象是显示解引用,而引用是编译器自己做了类似指针解引用的处理)。
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方把函数内容展开,从而替换对函数的调用,没有函数压栈的开销,内联函数可以提升程序运行的效率。
//定义两个数相加的内联函数
inline int Add(int a, int b)
{
return a + b;
}
优点
缺点
C++11中,使用auto定义变量时会自动识别变量的类型。使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。
int a = 10;
//auto自动识别b的类型为int
auto b = a;
int x = 10;
//声明指针类型
auto a = &x;//等价于auto* b = &x;
//声明引用,必须加上&
auto& c = x
auto a = 1, b = 2;
auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导,也就不能完成传入实参的类型检查
void TestAuto(auto a)
{}
// 此处代码编译失败,auto不能用来声明数组的元素类型
void TestAuto()
{
auto arr[] = {4,5,6};
}
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。
PS:与普通循环类似,可以用continue来结束本次循环直接进入下一次,也可以用break来跳出整个循环。
// 1.错误使用 //因为arrzuo作为实参参入后已经不是数组了,退化成了指针,for的范围不能确定 void TestFor(int arr[]) { for (auto& e : arr) { cout << e << endl; } } int main() { int arr[] = { 1,2,3,4,5 }; // 2.正确使用,此时arr代表整个数组,是有确定的范围的 for (auto& e : arr) { cout << e << " "; } return 0; }
NULL 预处理后:0
nullptr 预处理后:(void*)0
PS:C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。