C++从开始到放弃(第一天)
1.命名空间
创建命名空间
1.普通命名空间
namespace N1//以N1为命名空间名称
{
int a = 10;
}
2.设计嵌套空间
namespace N2//设计嵌套空间
{
int a = 1;
int b = 2;
namespace N3
{
int c = 3;
int b = 4;
}
}
- 同一个工程中允许存在多个相同名称的命名空间
使用命名空间:
1.使用using namespace + 命名空间名称或者只使用新开辟空间的一个元素。
using namespace N1;
using N1::a;//
int main()
{
printf("%d", a);
return 0;
}
2.加命名空间名称及作用域限定符::
printf("%d", N1 :: a);
3.使用嵌套空间
printf("%d", N2::N3::c);
2.C++的输入和输出
C++的标准输出
1.使用cout和cin时,必须包含< iostream >头文件以及std标准命名空间。
2.使用C++输入输出更方便,不需增加数据格式控制,比如:整形--%d,字符--%c
实现代码:
#include<iostream>
using namespace std;
int main()
{
int a;
int b;
int c;
int d;
cin >> a;
cin >> b >> c >>d;//输入的先后顺序,从左到右。
cout << a << endl;
cout << b << d << " "<< c << endl;//排序 b,c,d
system("pause");
return 0;
}
3.缺省函数(备胎函数)
概念:
声明或者定义函数的时候为函数的参数定义一个固定值,在传参的时候,如果没有指定实参,则使用这个固定值,否则使用实参。
分类:
1.全缺省参数
void TestFunc(int a = 10, int b = 20, int c = 30)//全缺省函数
{
cout << "" << a << endl;
cout << "" << b << endl;
cout << "" << c << endl;
}
2.半缺省函数
void TestFunc(int a, int b = 20, int c = 30)//半缺省函数
{
cout << "" << a << endl;
cout << "" << b << endl;
cout << "" << c << endl;
}
注意
1.半缺省参数必须 从右向左 给出,不能间隔着给。
2.不能在.h和.c中同时出现。
3.缺省值必须是常量或者说全局变量。
4.C语言不支持。
4函数重载
1.含义:
C++允许声明几个功能类似的同名函数,这些函数的形参必须不同。
例如:
#include<iostream>
using namespace std;
int Add(int a, int b)
{
return a;
}
int Add(double a, double b)
{
return b;
}
int main()
{
Add(10, 20);
Add(10.0, 20.0);
return 0;
}
2. extern “C”
C++中有些函数需要用C的风格来编译,在函数之前加extren"c",就是将函数按照C的风格来编译
extern "C" int Add(int left, int right);
{
return left + right;
}
int main()
{
Add(1,2);
return 0;
}
3.名字修饰(name Mangling)(重点)
函数运行时,需要经历以下几个阶段:预处理、编译、汇编、链接。
名字修饰就是在编译过程中,将函数,变量的名称重新改编的机制,也就是编译器通过某种算法,将函数修饰为全局唯一的变量。
运行C语言函数
void TestFunc(int a);
int main()
{
TestFunc(1);
return 0;
}
运行出错:
由于上面的函数只给了声明,没有给定义,因此函数报错,提示,函数找不到_TestFunc。从上图可以看出,C语言只是简单的在函数名前加了下划线,因此有两个或者多个函数名同时出现时,会出现冲突,导致系统报错
运行C++函数
void TestFunc(int a);
void TestFunc(double a);
int main()
{
TestFunc(1);
TestFunc(1.0);
return 0;
}
运行出错:
由上图可以看出,在c++中被修饰的不仅仅是TestFunc的名字,而是被修饰了更复杂的函数,被重新修饰的函数包括了:函数名称和函数之中的参数类型。这就是为什么C++可以命名同名函数的原因。只要参数列表不同,编译器在编译时通过对函数名字进行重新修饰,将参数类型包含在最终的名字中,就可保证名字在底层的全局唯一性。
5.引用
概念
引用并不是新开了一个空间,而是一个已存在的空间的别名,编译器不会另开一个空间给他,而是和她命名的空间同用一个内存空间。
例子:
int main()
{
///*Add(10, 20);
//Add(10.0, 20.0);*/
//TestFunc(1);
//TestFunc(1.0);
int a = 10;
int& ra = a;
printf("%p\n", &a);
printf("%p\n", &ra);
system("pause");
return 0;
}
运行结果:
1.引用特性
1.引用在定义时必须初始化
2.一个变量可以有多个引用
3.引用一旦有一个实体,就不能有另一个实体。
2.常引用
{
const int a = 10;
//int &ra = 0;//该语句编译出错,a为常数,本身应该为定值。
const int& ra = a;
double b = 0;
//int* rb = b;//错误,类型不同
const int &rb = b;//可能会丢数据,隐式类型转换。
//int &c = 10;//不能将int形转换为int*形
}
使用场景
1.做参数
2.做返回值
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :" << ret << endl;
system("pause");
return 0;
}
运行结果
似乎是对的,但是如果在数据加上Add(3, 4);之后呢?
结果:
同时系统提出警告:
得出结论
函数返回时,离开作用域之后,其栈上的空间已经还给了系统,因此不能用栈上的空间作为引用类型返回。
3.传引用的效率远高于传指针的效率。
因为在传参和返回的时候,
函数传递的会是一份临时的拷贝,导致传值或者指针的效率非常低,
因此最好使用引用。
4.引用和指针的区别(重点)
不同点:
1.引用在定义时必须初始化,指针没有必要。
2.引用在初始化了一个实体后,就不能再引用其他的实体。而指针可以在任何时候指向任何一个同类型实体。
3.没有NULL引用,有空指针。
4.在sizeof中含义不同,引用的结果为引用的类型大小不同,但指针始终是四个字节(32位机器下)
5.引用自加是指所引用的实体增加1,指针自加是指针向后偏移一个单位。
6.有多级指针,没有多级引用。
7.引用相对来说更安全。