c++入门
命名空间
在c++中,为了避免标识符的命名发生冲突,标准c++引入了关键字namespace(命名空间),可以更好的控制标识符的作用域。
先看一个程序:
#include <iostream>
using namespace std;
int a=40;
namespace AA1
{
int a=20;
}
namespace AA2
{
int a=30;
}
namespace AA3
{
int a=50;
namespace AA4
{
int a=60;
}
}
int main()
{
cout<<AA1::a<<endl;//访问AA1空间内的a=20
cout<<AA2::a<<endl;//访问AA2空间内的a=30
cout<<a<<endl;//访问全局变量std空间的a=40
cout<<AA3::a<<endl;//访问AA3空间内的a=50
cout<<AA3::AA4::a<<endl;//访问AA3空间内嵌套的AA4中的a=60
return 0;
}
命名空间可以是全局的,也可以是一个命名空间嵌套一个命名空间,但不能位于类和代码块中。其作用是:建立一些互相分隔得作用域,把一些全局实体分隔开来,解决名字冲突的问题。
2.C++基本的输入输出流(简单介绍一下就行)
1>.标准输入流对象cin
cin是标准的输入流对象,在程序中用于代表标准输入设备,通常指键盘。运算符”>>”表示将从标准输入流对象cin读数的数值传给右方指定的变量。cin必须与输入运算符”>>”一起使用。
cin>>x;
此时,用户从键盘输入的数值会自动地转换为变量x的类型。
注意:x必须是基本数据类型,而不能是void类型。
运算符”>>”允许用户连续输入一连串的数据,例如 :
cin>>a>>b>>c;
2>标准输出流对象cout
cout是标准输出流对象,在程序中用于代表标准输出设备,通常指屏幕。运算符”<<”在c++中仍保持c中的”左移”操作,表示将右方变量的值写到 标准输出流cout对象中,即显示在屏幕上。cout必须与输出运算符”<<”一起使用。
cout<<y;
变量y的值将显示在屏幕上。
使用插入运算符”<<”进行输出操作时,可以把多个不同类型的数据组和在一条语句中,也可以输出表达式的值,例如:
cout<<a+b<<c;
它按书写顺序将a+b和c的值输出到屏幕上。
int n=456;
double d=3.1416;
cout<<"n="<<n<<",d="<<d<<'\n';
上述语句的输出结果为:
n=456,d=3.1416
3.重载(C++为什么支持重载?)
重载:在c++中,在同一个作用域中,函数名相同,函数参数的类型不同,或者参数的个数不同,或者两个兼而有之,即可构成重载。
看一个例子:
#include <iostream>
using namespace std;
int cube(int i)//gcc编译后,命名为_z4cubei
{
return;
}
int cube(char j)//gcc编译后,命名为_z4cubec
{
return;
}
int cube(int i,char j)//gcc编译后,命名为_z4cubeic
{
return;
}
int cube(char j,int i)//gcc编译后,命名为_z4cubeci
{
return;
}
int main()
{
return 0;
}
规定在c中,在同一个作用域中,函数名唯一。而在c++中,要求在同一的作用域中,函数签名唯一。
那么什么是函数签名呢?
函数签名即函数名+参数列表。代码段在被编译时,会根据函数名生成函数的调用地址,函数名就会发生命名置换。比如:
int cube(int i)
{
}
gcc编译后,转到汇编代码会变成_Z4cubei,其中_Z是规定前缀,4是函数名的字符个数,i是参数列表的首字母。由此规则,上述代码的不同函数的函数签名如注释所示。
4.C++缺省参数
所谓缺省参数,顾名思义,就是在声明函数的某个参数的时候为之指定一个默认值,在调用该函数的时候如果采用该默认值,你就无须指定该参数。缺省参数使用主要规则:调用时你只能从最后一个参数开始进行省略,换句话说,如果你要省略一个参数,你必须省略它后面所有的参数,即:带缺省值的参数必须放在参数表的最后面。 缺省值必须是常量。显然,这限制了缺省参数的数据类型,例如动态数组和界面类型的缺省参数值只能是 nil;至于记录类型,则根本不能用作缺省参数。 缺省参数必须通过值参或常参传递。
缺省参数分为两种:全缺省和半缺省
看一个例子:
#include <iostream>
using namespace std;
int Add1(int a,int b=10)// 半缺省参数
{
return a+b;
}
int Add2(int a=10,int b=20)// 半缺省参数
{
return a+b;
}
int main()
{
cout<<Add1(0)<<endl; //0+10=10
cout<<Add1(10,20)<<endl;//10+20=30
cout<<Add2()<<endl;//10+20=30
cout<<Add2(20,30)<<endl;//20+30=50
return 0;
}
注意:这种缺省是不允许的:int Add(int a=0,int b);
5.指针和引用(概念、使用方法、做参数、做返回值的作用,指针和引用的区别)
★ 相同点:
- 都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
★ 区别:
指针是一个实体,而引用仅是个别名;
引用使用时无需解引用(*),指针需要解引用;
引用只能在定义时被初始化一次,之后不可变;指针可变;
引用“从一而终” ^_^
引用没有 const,指针有 const,const 的指针不可变;
引用不能为空,指针可以为空;
“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。
- 指针和引用的自增(++)运算意义不一样;
★ 联系
引用在语言内部用指针实现(如何实现?)。
对一般应用而言,把引用理解为指针,不会犯严重语义错误。引用是操作受限了的指针(仅容许取内容操作)。
引用是C++中的概念,初学者容易把引用和指针混淆一起。一下程序中,n 是m 的一个引用(reference),m是被引用物(referent)。
int m;
int &n = m;
n 相当于m 的别名(绰号),对n 的任何操作就是对m 的操作。例如有人名叫王小毛,他的绰号是“三毛”。说“三毛”怎么怎么的,其实就是对王小毛说三道四。所以n 既不是m 的拷贝,也不是指向m 的指针,其实n就是m 它自己。
引用的一些规则如下:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
以下示例程序中,k 被初始化为i 的引用。语句k = j 并不能将k 修改成为j 的引用,只是把k 的值改变成为6.由于k 是i 的引用,所以i 的值也变成了6.
int i = 5;
int j = 6;
int &k = i;
k = j; // k 和i 的值都变成了6;
引用的格式为:类型& 引用变量名=已定义过的变量名;
void fun()
{
int a=10;
int& b=a;//引用a的变量名,b的值为10
}
函数参数引用
如果想要通过函数调用来交换两个变量的值时,在传递参数的时候通常传变量的地址,接收时用指针来接收。
int swap(int *a,int *b)
{
int tmp=*a;
*a=*b;
*b=tmp;
}
这类通过指针接收参数叫指针传递,但是指针会增加程序的时间,刚刚了解到引用是给一个变量起个别名,给以通过修改这个别名的内容达到修改这个变量内容的目的。
int swap(int& a,int& b)
{
int tmp=*a;
a=b;
b=tmp;
}
这类叫引用传递,它是直接通过修改别名值来达到交换目的的,这类传递的运行时间会比指针短。
传引用做返回值
int& fun(int a, int b)
{
int ret = a+b;
return ret;
}
int main()
{
int a = 10, b = 20;
int& c = fun(a, b);
cout<<c<<endl;
system("pause");
return 0;
}
返回时是返回值的地址存储在寄存器里,然后接收的时候是接收的这个变量的引用,虽然结果是正确的,但是实际上函数调用完之后,空间就被收回了。如果在调用一个其他的函数,那么这个接收的结果一定会发生变化,是一个随机的值。
void f(int a, int b)
{
int s = a+b;
}
int fun(int a, int b)
{
int ret = a+b;
return ret;
}
int main()
{
int a = 10, b = 20;
int c = fun(a, b);
cout<<c<<endl;
f(a, b);
cout<<c<<endl;
system("pause");
return 0;
}
注意:
1、不要返回一个临时变量的引用
2、如果返回对象出了当前函数的作用域依旧存在,则最好使用引用返回,这样效率更高。