1.C++入门(中)

简介: 1.C++入门(中)

1.缺省参数

1.概念

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参,就采用缺省值

  • 全缺省参数
void Func(int a = 10, int b = 20, int c = 30)
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl;
 }
  • 半缺省参数
void Func(int a, int b = 10, int c = 20)
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl;
 }

1. 半缺省参数必须 从右往左依次 来给出,不能间隔着给

2. 声明与定义分开时,缺省参数不能在函数声明和定义中同时出现,只能在声明出现

 //a.h
  void Func(int a = 10);
  
  // a.cpp
  void Func(int a = 20)
 {}
  
  // 注意:如果生命与定义位置同时出现,
恰巧两个位置提供的值不同,那编译器
就无法确定到底该用那个缺省值。

3.缺省值必须是常量或者全局变量

4.写死的方式都挺挫的,对于长度不定的函数,可以给出官方指导值

   如:STInit (ST* ps,int n=4)   n=4就是指导值

2.函数重载

函数重载:是函数的一种特殊情况,C++ 允许在 同一作用域中 声明几个功能类似 的同名函数,这些同名函数的形参列表 ( 参数个数 或 类型 或 类型顺序 ) 不同,常用来处理实现功能类似数据类型不同的问题

#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
 cout << "int Add(int left, int right)" << endl;
 return left + right;
}
double Add(double left, double right)
{
 cout << "double Add(double left, double right)" << endl;
 return left + right;
}
// 2、参数个数不同
void f()
{
 cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
 cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
 cout << "f(char b, int a)" << endl;
}
int main()
{
 Add(10, 20);
 Add(10.1, 20.2);
 f();
 f(10);
 f(10, 'a');
 f('a', 10);
 return 0;
}

原理--名字修饰

为什么 C++ 支持函数重载,而 C 语言不支持函数重载呢?

在 C/C++ 中,一个程序要运行起来,需要经历以下几个阶段: 预处理、编译、汇编、链接

这个知识忘了的可以看一下这篇博客:

23.编译和链接

1. 实际项目通常是由多个头文件和多个源文件构成,而通过 C 语言阶段学习的编译链接,我们可以知道,【当前 a.cpp 中调用了 b.cpp 中定义的 Add 函数时】,编译后链接前, a.o 的目标文件中没有 Add 的函数地址,因为 Add 是在 b.cpp 中定义的,所以 Add 的地址在 b.o 中。那么怎么办呢?

2. 所以链接阶段就是专门处理这种问题, 链接器看到 a.o 调用 Add ,但是没有 Add 的地址,就会到 b.o 的符号表中找 Add 的地址,然后链接到一起 。

3. 那么链接时,面对 Add 函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。

4.  通过下面我们可以看出 gcc(也就是支持C语言) 的函数修饰后名字不变。而 g++(也就是支持c++) 的函数修饰后变成【 _Z+ 函数长度 + 函数名 + 类型首字母】。 采用 C 语言编译器编译后结果

编译C++后

5. 通过这里就理解了 C 语言没办法支持重载,因为同名函数没办法区分。而 C++ 是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载 。

结论:

在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中

注意:

如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时函数时编译器没办法直到返回值,所以无法进行区分。

3.引用

1.概念

  引用是不新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

定义:  类型& 变量名(要取的别名) = 引用实体;

void TestRef()
{
    int a = 10;
    int& ra = a;//<====定义引用类型
    printf("%p\n", &a);
    printf("%p\n", &ra);
}

注意: 引用类型必须和引用实体是同种类型的

2.特性(就是取别名)

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用(可以一对多)
  3. 引用一旦引用一个实体,再不能引用其他实体(指向不可变)
void TestRef()
{
  int a = 10;
  // int& ra;   // 要初始化
  int& ra = a;
  int& rra = a;//可以一对多
  printf("%p\n%p\n%p\n", &a, &ra, &rra);
  int b = 20;
  ra = b;//不可改变指向
  printf("%p", &ra);
}

3.常引用

常引用要加const前缀

上面的隐式类型转化中,会产生int临时变量(具有常量性),相当于是一个将d拷贝到临时变量中,再拷贝到rd中,所以rd接收到的是一个常量性数值,要加const

4.使用场景

a.做参数

例如实现值的交换

void Swap(int& left, int& right)
{
   int temp = left;
   left = right;
   right = temp;
}

b.做返回值

适用范围:

1.malloc  2.全局  3.static

结论: 如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。否则容易造成野指针

优点:1.减少拷贝,提高效率(大对象/深拷贝)

          2.修改返回值

4.传值.传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

#include <time.h>
struct A{ int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a;}
// 引用返回
A& TestFunc2(){ return a;}
void TestReturnByRefOrValue()
{
 // 以值作为函数的返回值类型
 size_t begin1 = clock();
 for (size_t i = 0; i < 100000; ++i)
 TestFunc1();
 size_t end1 = clock();
 // 以引用作为函数的返回值类型
 size_t begin2 = clock();
 for (size_t i = 0; i < 100000; ++i)
 TestFunc2();
 size_t end2 = clock();
 // 计算两个函数运算完成之后的时间
 cout << "TestFunc1 time:" << end1 - begin1 << endl;
 cout << "TestFunc2 time:" << end2 - begin2 << endl;
}

可以发现:

通过上述代码的比较,发现 传引用效率大于传值

//持续更新,敬请期待~


相关文章
|
1月前
|
编译器 C++
C++入门12——详解多态1
C++入门12——详解多态1
38 2
C++入门12——详解多态1
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
24 3
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
30 2
|
1月前
|
C++
C++入门13——详解多态2
C++入门13——详解多态2
80 1
|
1月前
|
程序员 C语言 C++
C++入门5——C/C++动态内存管理(new与delete)
C++入门5——C/C++动态内存管理(new与delete)
68 1
|
1月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
20 1
|
1月前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
33 1
|
1月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
42 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
1月前
|
存储 安全 编译器
【C++打怪之路Lv1】-- 入门二级
【C++打怪之路Lv1】-- 入门二级
23 0
|
1月前
|
自然语言处理 编译器 C语言
【C++打怪之路Lv1】-- C++开篇(入门)
【C++打怪之路Lv1】-- C++开篇(入门)
26 0