c++入门
命名空间
1.命名空间的标准使用格式
什么是命名空间呢,简单来说当我们定义一些变量或者函数时会与头文件发生重复,为了使自己的变量或者函数能够正常使用,我们会将这些变量或者函数写进自己的命名空间中,以便于后续调用
#include<stdio.h>
#include<iostream>
namespace SN
{
int x = 5;
int Add(int a, int b)
{
return a + b;
}
struct A
{
int a = 2;
int b = 3;
int Add(int a, int b)
{
return a + b;
}
};
}
//对于主函数来说,不能直接使用命名空间中的变量和函数,如果想要使用,下面有三种使用方式:
//第一种使用方式,全部展开:公开命名空间中的权限,之后我们就能正常使用这些变量,函数等写入命名空间的东西。
using namespace SN;
//第二种使用方式,部分展开:顾名思义,与全部展开的区别就是只公开部分权限
using SN::x;
int main()
{
printf("%d",x);
//第三种使用方式,在使用时展开
printf("%d",SN::x);
struct SN::A a;
return 0;
}
//这三种使用方式可以同时使用,一般来说系统不会冲突
//个人建议第二种使用方式,因为第三种太过于繁琐,第一种方式会与系统函数产生冲突,下面会讲
2.为什么要使用命名空间
(一)为了防止与头文件包含的函数或者其他文件中的变量、函数等发生重名
(二)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<iostream>
namespace SN
{
int x = 4;
int Add(int a, int b)
{
return a + b;
}
struct A
{
int a = 2;
int b = 3;
int Add(int a, int b)
{
return a + b;
}
};
}
int Add(int x, int y)
{
return (x + y) * 10;
}
//第三种
using SN::Add;
//展开之后全局范围中的函数Add会与局部变量中的Add函数发生冲突,无法编译
int main()
{
//第一种情况,调用范围为全局的函数,不会与命名空间冲突
printf("%d\n",Add(1,2));
//第二种,范围只在这次调用时展开
printf("%d\n",SN::Add(1, 2));
}
第一和第二种均在没有全部和部分展开之下进行
3.using namespace std;
我们经常会在c++的开头写上这么一句,那么为什么要写上,这一句的作用又是什么?
1.std是c++标准库的命名空间
2.避免与自己的命名空间发生冲突
#include<iostream>
//因为头文件iostream里面使用了命名空间来定义cout,如果不加上这句话,即使包含头文件,cout无法使用
using namespace std;
/*namespace std
{
...
}*/
int main()
{
cout << "hello world" << endl;
//当然如果不想展开也可以这么使用(或者部分展开)
std::cout << "hello world" << std::endl;
return 0;
}
4.命名空间的合并
当我们在两个不同头文件(A.h、B.h)里定义了同一名称的命名空间,当我们在源文件(test.c)包含之后,这两个文件中的命名空间的内容会合并在一起(当然要避免定义重复)
缺省参数
以下规则记住就行
全缺省函数
#include<stdio.h>
#include<iostream>
#include<iostream>
using namespace std;
//全缺省函数:相比以往函数,每个形参都给了值
//其特点是,即使调用时没有给相对应的值也能调用
//注意点:调用时必须从左到右依次给值,可以不给值,但是不能跳着给值
void Func1(int a = 1, int b = 2, int c = 3)
{
cout << "a=" << a ;
cout << "b=" << b ;
cout << "c=" << c << endl;
}
void Func2(int a, int b, int c)
{
cout << "a=" << a ;
cout << "b=" << b ;
cout << "c=" << c << endl;
}
int main()
{
Func1();
Func1(7);
Func1(7,8);
Func1(7,8,9);
/*错误调用例子
Func1(,8,9);*/
Func2(4, 5, 6);
return 0;
}
半缺省
//半缺省函数的形参必须从右向左给值,同样不能跳着给值
#include<iostream>
using namespace std;
//半缺省函数
void Func1(int a, int b, int c = 3)
{
cout << "a=" << a;
cout << "b=" << b;
cout << "c=" << c << endl;
}
void Func2(int a, int b = 2, int c = 3)
{
cout << "a=" << a;
cout << "b=" << b;
cout << "c=" << c << endl;
}
int main()
{
/*错误案例
Func1(4)*/
Func1(4, 5);
Func1(4, 5, 6);
Func2(7);
Func2(7,8);
Func2(7,8,9);
return 0;
}
缺省函数声明和定义
如果缺省参数声明和定义分离,那么声明时要给缺省参数,定义不给缺省参数。
函数重载
C语言不允许同名函数,但是c++可以,但是需要构成函数重载。
函数重载的特点:函数名相同,参数不同(顺序,类型,个数)
引用
引用概念
引用不是重新定义一个变量,只是为被引用的变量起了个别名,因此,引用一个变量也不会开辟一块空间,实际上引用创建的对象和引用的对象共用一块空间。
具体格式
类型& 引用变量名 = 引用实体
int main()
{
int a=1;
int& b=1;
int* p;
int* &pp=p;
//a,b指向同一块空间
printf("%p",&a);
printf("%p",&b);
b++;
//随着b的改变,a也发生改变
printf("%d",a);
printf("%d",b);
}
引用特性
1.引用在定义时先要初始化(不给实体赋值也能引用);
2.一个变量可以有多个别名;
3.引用一旦引用一个实体,就不能引用其他实体了;
int main()
{
/*错误案例
int &a;*/
int a = 10;
int& b = a;
int& c = b;
return 0;
}
引用作返回值
//传值返回
int A()
{
int n=10;
//由于n属于局部变量,n在A的调用结束后销毁
return n;
}
int main()
{
//n虽然已经销毁,但是ret仍然能够被赋值与n相同的值
//因为n在销毁之前拷贝到寄存器中,寄存器又充当返回值赋值给ret
int ret =A();
return 0;
}
//传引用返回
int& A()
{
int n=10;
return n;
}
int main()
{
//因为传引用返回了n的别名,n已经在A的调用结束时销毁
//由于不同环境下,n可能被置成随机值,也可能保留原值。无论如何,这种调用方式是不安全的、不规范的
int ret =A();
return 0;
}
传值传参和传引用传参的效率对比
传引用传参(任何时候都可以用):
1.提高效率
2.输出型参数(形参的修改,影响的实参)
传引用返回(出了函数作用域对象还在才可以使用)
1.提高效率
2.修改返回对象
引用过程注意点
//引用过程中
//权限可以平移
//权限可以缩小
//权限不可以放大
int main()
{
const int a = 0;
//权限的放大
//int& b = a;
//权限的平移
const int& c = a;
//权限的缩小
int x = 0;
const int& y = x;
return 0;
}
小知识:
int main()
{
int i = 0;
/*错误案例
double& b = i*/
//这里的i首先会传给一个临时变量,由于临时变量具有常属性,所以要注意引用使用注意事项
const double& b = i;
}
内联函数(inline)
标准格式:inline 返回值 函数名(参数);
内联函数不能声明和定义分离,会出现链接错误。
auto关键字
int main()
{
//自动推导类型
int a = 0;
auto b = a;
auto c = &a;
auto& d = a;
//一般场景没有什么价值
//类型很长,就会有价值,简化代码
std::vector<std::string> v;
std::vector<std::string>::inerator it = v.begin();
auto it = v.begin();
}
1.auto不能作为函数的参数
void TestAuto(auto a)
{}
2.auto不能直接用来声明数组
void TestAuto()
{
int a[]={1,2,3}
auto b[]={4,5,6};
3.获取类型名称
int main()
{
int a;
double b;
float c;
cout << typeid(a).name() <<endl;
cout << typeid(b).name() <<endl;
cout << typeid(c).name() <<endl;
}
4.遍历数组
int main()
{
int arr[]={1,2,3,4,5}
//这里i只是拷贝,这里arr是数组
for(auto i : arr)
{
x+=2;
}
//通过引用可以改变里面的值
for(auto& i : arr)
{
x+=2;
}
for(auto i : arr)
{
cout << i << " ";
}
return 0;
}