C++笔记 --- 函数与命名空间

 

目录

 

函数
命名空间

 (本章节中例子都是用 VS2005 编译调试的)

 

函数

 [格式][返回值][参数][可变参数][内联函数][函数重载]

格式:

返回类型 函数名 (函数参数类型 函数参数, ....)

  函数体(执行部分) 
}

//如果没有形参可以直接在函数名后面加()或者 (void) 

 

返回值说明:

有返回值函数:

  • 必须使用return语句并加上返回类型的返回值,且遇到第一个return语句函数就结束,在函数执行完后,语句中的函数调用处将被替换为返回值
  • 其返回值值必须为返回类型或可转为返回类型的类型,且不可为函数内部变量因为内部变量会在函数结束时候释放空间,但可用new来开辟变量然后返回出去
  • 若返回值为地址,在函数名前加‘*’

无返回值函数:

  • 声明,定义前用void表示无返回值, 函数允许用return;来退出函数

 例子:

View Code
 1 // 例1 -- 有返回值
 2 double max(double a,double b)
 3 {
 4     return a>b?a:b;
 5 }
 6 
 7 // 例2 -- 无返回值
 8 void show()
 9 {
10     cout<<"hello! "<<endl;
11     return;  //这句可加可不加,但是如果你有时候需要在某些语句直接跳出函数的话就需要加 return; 了
12 }
13 
14 // 例3 
15 void outsum(int n)
16 {
17     if(n<10)
18     {
19         cout<<"请传递 10 以上的数值!"<<endl;
20         return;
21     }
22     int sum = 0;
23     for(int i=1 ; i<n+1 ; i++)
24         sum += i;
25     cout<<"从 1 一直累加到 "<<n<<" 的和为 "<<sum<<endl;
26 }
27 /********************************************************************************
28 当传递 5 给 outsum 函数时,即 outsum(5); 是输出的是:      请传递 10 以上的数值!
29 当传递 12 给 outsum 函数时,即 outsum(12); 是输出的是:     从 1 一直累加到 12 的和为 78
30 ********************************************************************************/

 

参数说明:

形参传递:  

  • 按值   形参另开辟一个新空间为实参副本
  • 按址   形参为实参的引用

例子:

View Code
 1 void exchange1(int a,int b)
 2 {
 3     cout<<"调用传值函数实现变量值互换:"<<endl;
 4     int temp = b;
 5     b = a;
 6     a = temp;
 7     cout<<"传值函数中交换的结果:  a = "<<a<<";  b = "<<b<<endl;
 8 }
 9 void exchange2(int &a,int &b)
10 {
11     cout<<"调用传址函数实现变量值互换:"<<endl;
12     int temp = b;
13     b = a;
14     a = temp;
15     cout<<"传址函数中交换的结果:  a = "<<a<<";  b = "<<b<<endl;
16 }
17 void main()
18 {
19     int a=5,b=10;
20     
21     exchange1(a,b);
22     cout<<"传值函数调用后的结果:  a = "<<a<<";  b = "<<b<<endl<<endl;
23     exchange2(a,b);
24     cout<<"传址函数调用后的结果:  a = "<<a<<";  b = "<<b<<endl;
25 
26     system("pause");
27 }

  输出结果:

C++笔记 --- 函数与命名空间_第1张图片

调用中形参允许无关紧要的转换:  

  实参                      形参                            
 Type               Type &
 Type &            Type
 Type[] *             Type &
 Type(argment_list)      Type (*)(argment_list)
 Type             const Type
 Type             volatile Type
 Type *            const Type
 Type *            volatile Type

默认形参:

说明:

    • 当一个函数既有定义又有声明时,形参的默认值必须在声明中指定,而不能放在定义中指定.只有当函数没有声明时,才可以在函数定义中指定形参默认值
    • 默认值定义必须遵守从右到左的顺序,若某个形参无默认值,则它左边参数就不能有默认值
    • 形参默认值可以是全局常量,全局变量,表达式,函数调用,但不能为局部变量

例子:

默认新参:

View Code
 1 void show(int a = 5)
 2 {
 3     cout<<"the value of a is "<<a<<endl;
 4 }
 5 void main()
 6 {
 7     show(8);
 8     show();     //不传惨则参数等于默认值即 5
 9     system("pause");
10 }
11 /**************************
12 输出结果:
13 the value of a is 8
14 the value of a is 5
15 请按任意键继续. . .
16 **************************/

一个关于传递一维数组的例子:

View Code
 1 void output(int *p,int b)
 2 {
 3     cout<<"元素 "<<b<<" 的值为: "<<*(p+b)<<endl;
 4 }
 5 
 6 void main()
 7 {
 8     int a[5]={1,2,3,4,5};
 9     a[0]=3;
10     for(int i=0 ; i<5; i++)
11         output(a,i);
12     system("pause");
13 }
14 /****************************************
15 输出结果:
16 元素 0 的值为: 3
17 元素 1 的值为: 2
18 元素 2 的值为: 3
19 元素 3 的值为: 4
20 元素 4 的值为: 5
21 请按任意键继续. . .
22 ****************************************/

一个复杂点点的声明:

1 void (*signal(int signum,void(* handler)(int)))(int);
2 //一个 linux 里面的设置信号处理函数的函数声明;

说明:

  • 返回值:  为一个 void(*   )(int) 的函数指针
  • 函数名:  signal为此函数函数名
  • 参数列表:
    • 一个 int 类型参数
    • 一个是 void(* )(int) 类型的函数指针

参数可变函数:

声明格式:

返回类型 函数名 (形参表,....)
{
  函数体
}

注意

  • C++的cstdarg标头档中也提供这样的机能;虽然与C的标头档是相容的,但是也有冲突存在
  • 不定参数函式的参数数量是可变动的,它使用省略号来忽略之后的参数,在C,省略符号之前必须要有逗号既不定参数函式最少要有一个命名的参数;在C++,则没有这种强制要求 (char *wrong(...);在C是不被允许的)
  • 具体看<stdarg.h>头文件

[查看具体说明可以点此链接]

 例子:

View Code
 1 void output(int n, ...);
 2 void main()
 3 {
 4     output(3,"王一",12,"李二",5,"赵三",58);
 5     system("pause");
 6 }
 7 void output(int n, ...)
 8 {
 9     va_list ap;
10     va_start(ap,n); //起到初始化,使用得 ap 指向可变参数的第一个参数,即 n 处
11     while(n--)
12     {
13         char* name=va_arg(ap,char*);  
14 //获得当前 ap 所指向的参数,并使 ap 指向可变参数的下一个参数,并且要指明获得的参数类型char* 为需要获得的参数的类型.
15         int age=va_arg(ap,int);    //同上,int为参数类型
16         cout<<"name :"<<name<<",age="<<age<<endl;
17     }
18     va_end(ap);  //结束可变参数获取
19 }
20 /***************************************
21 输出结果:
22 name :王一,age=12
23 name :李二,age=5
24 name :赵三,age=58
25 请按任意键继续. . .
26 ***************************************/

 

内联函数:

定义:

内联函数的额编译与其他程序代码“内联”起来编译器将相应的函数代码替换函数调用,加快了运行速度,但需要更多内存

声明格式:

inline 返回类型 函数名 (形参表....) 
{
  函数体
}

例子:

1 inline int show() 
2 {
3     cout<<"this is inline function!"<<endl;
4 }

详细介绍链接

 

函数重载:

目的与作用:

当将要定义一组函数,使它们执行一系列的操作,但是它们是应用在不同的参数类型上的但是操作功能和目的是一样的,此时我们可以选择重载函数

要求:

  • 同的函数名,不同的形参表(参数数目或类型不同)
  • 函数的调用取决于实参类型或数目,调用出匹配的函数[不能利用返回类型与参数引用来进行函数重载]

例子:

View Code
 1 // 例1 -- 基于参数类型-------------------------------
 2 double max(double a,double b)
 3 {
 4     return a>b?a:b;
 5 }
 6 int max(int a,int b)
 7 {
 8     return a>b?a:b;
 9 }
10 // 例2 -- 基于参数个数--------------------------------
11 int max(int a,int b)
12 {
13     return a>b?a:b;
14 }
15 int max(int a,int b,int c)
16 {
17     if(a>b)
18         if(a>c)
19             return a;
20         else
21             return c;
22     else 
23         if(b>c)
24             return b;
25         else
26             return c;
27 }
28 // 例3 -- 基于参数位置--------------------------------
29 double max(double a,int b)
30 {
31     return (double)(a>(double)b?a:b);
32 }
33 double max(int a,double b)
34 {
35     return (double)((double)a>b?a:b);
36 }

 

[返回目录]

 

 

命名空间

[格式][创建别名][访问命名空间的成员][using声明与using编译]

格式:

namespace 空间名称
{
  空间变量成员;
  空间成员函数;

例子:

 1 namespace nstd
 2 {
 3     int a;
 4     namespace sub_nstd
 5     {
 6         void show()
 7         {
 8             cout<<a<<endl;
 9         }
10     }
11 }

 

给名称空间创建别名:

格式:  

namespace 别名 = 原命名空间名(可以是嵌套的形式);

例子:

View Code
 1 // 例1 -- 给命名空间取别名无嵌套模型的
 2 namespace o_nstd = nstd;
 3 using o_nstd::a;    //此时的 o_nstd::a 相当于 nstd::a
 4 a = 5;
 5 
 6 
 7 // 例2 -- 给命名空间取别名有嵌套模型的
 8 namespace o_nstd = nstd::sub_nstd;
 9 using o_nstd::show;  //此时的 o_nstd::show 相当于 nstd::sub_nstd::show
10 show();

 

作用:

一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中(所以当多个文件要共用一个变量时候使用在命名空间中声明变量,而不是使用外部全局变量或静态全局变量)

 

访问命名空间中的成员:

  • 名称空间 将 using namespace + 空间名称放在函数定义之前.让文件中的所有函数都能够使用名称空间中的所有元素
  • 将 using namespace + 空间名称放在特定函数里让函数能用名称空间里所有元素
  • 将 using std::cout 在文件中,让该所用函数可以使用指定元素cout
  • 将 using std::cout 放入函数里,让该函数可以使用指定元素cout
  • 使用前缀 std:: 来使用其中的cout元素,std::cout

   例子:

View Code
 1 // 例1 -- 使用全局 using 编译 -----------------------
 2 using namespace std;
 3 void show()
 4 {
 5     cout<<"输入你要输入的数:   ";
 6 }
 7 void main()
 8 {
 9     int i;
10     show();
11     cin>>i;
12     cout<<"你输入的数为:  "<<i<<endl;
13 }
14 
15 // 例2 -- 使用局部 using 编译 -----------------------
16 void show()
17 {
18     cout<<"输入你要输入的数:   ";//报错
19 }
20 void main()
21 {
22     using namespace std;
23     int i;
24     show();
25     cin>>i;
26     cout<<"你输入的数为:  "<<i<<endl;
27 }
28 
29 
30 // 例3 --  全局使用 using 声明 -----------------------
31 using std::cout;
32 using std::cin;
33 using std::endl;
34 void show()
35 {
36     cout<<"输入你要输入的数:   ";
37 }
38 void main()
39 {
40     int i;
41     show();
42     cin>>i;
43     cout<<"你输入的数为:  "<<i<<endl;
44 }
45 
46 // 例4 --  局部使用 using 声明 -----------------------
47 void show()
48 {
49     cout<<"输入你要输入的数:   "; //报错
50 }
51 void main()
52 {
53     using std::cout;
54     using std::cin;
55     using std::endl;
56     int i;
57     show();
58     cin>>i;
59     cout<<"你输入的数为:  "<<i<<endl;
60 }
61 
62 // 例5 -- 使用命名空间方法 -----------------------
63 void show()
64 {
65     std::cout<<"输入你要输入的数:   ";
66 }
67 void main()
68 {
69     int i;
70     show();
71     std::cin>>i;
72     std::cout<<"你输入的数为:  "<<i<<std::endl;
73 }

 

using声明与using编译:

  • using声明  
    用例子解析使用方法:
    using std::cout<用到 cout 函数时候可省略名称空间 std:: 直接使用 cout 便可 例子同上>
  • using编译  
    用例子解析使用方法:
    using namespace std<当用到名称空间中变量或函数时候,命名空间( std:: )可省略从而直接使用里面的变量和成员函数  例子同上>

 

using声明与using编译的区别:

使用using 编译指令导入一个名称空间中所有的名称与使用多个using 声明是不一样的,而更像是大量使用作用域解析操作符。使用using 声明时,就好像声明了相应的名称一样。如果某个名称己经在函数中声明了,则不能用using 声明导入相同的名称。然而,使用using 编译指令时,将进行名称解析,就像在包含using 声明和名称空间本身的最小声明区域中声明了名称一样

 

注意

  • 不要再头文件中使用using编译与声明,因为当名称空间与声明区定义了相同的名称,用using声明的话,会使这两个名称会发生冲突而出错
  • 对于using声明,首先将其作用域设置为局部而非全局
  • 注意在定义该命名空间的作用域中必须是唯一的
  • 命名空间可以再全局作用域或其他作用域内部定义,但不能在函数或类内部定义
  • 命名空间名字后面接着花括号括住的一块声明与定义,可以出现在全局作用域的任意声明
  • 与其他作用域不同的是由命名空间可以在几部分中定义,可以在命名空间中定义新的命名空间,然后需要调用新命名空间中得变量时候,需要把包含变量的命名空间一级一级的写出来
  • 在默认情况下,名称空间的声明的名称链接性为外部的(除非引用了常量)
  • 当有冲突时,便须把名称空间补出来(例:myth::fetch; jill::fect )
  • 不能在命名空间的定义中声明(另一个嵌套)子命名空间,只能在命名空间定义子命名空间
  • 可以再名称空间里使用using编译与using声明
  • 命名空间的成员,是在命名空间中花括号内声明名称,可以再命名空间定义内,定义名称空间成员(内定义)(空间成员:类,变量,函数,子命名空间)也可以再命名空间的定义内声明成员,而在命名空间的定义外,定义命名空间成员

 

 

[返回目录]

 

你可能感兴趣的:(C++笔记 --- 函数与命名空间)