C++学习_2

一. 简介

        Day02,主要学习函数的类别及特点

二. 主要内容

 1. 内联函数

        内联函数是指用inline关键字修饰的函数。在类内定义的函数被默认成内联函数。内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。一般在代码中用inline修饰,但是能否形成内联函数,需要看编译器对该函数定义的具体处理。

 a. 定义方式

        使用关键字inline进行修饰函数。如下所示

inline int Add_int(int a, int b)
{
	return a + b;
}

 b. 运行原理

        通过其概念可知,在实际问题中,在调用内联函数时并不会进行真正的调用,而是在调用处直接展开函数体,减少开栈清栈开销,需要注意的是内联函数的函数体执行开销需小于开栈清栈开销,否则不必定义为内联函数。

        具体使用情况如下所示

inline int Add_int(int a, int b)
{
	return a + b;
}
int main()
{
	int c = 0;
	c = Add_int(10, 56);	// 此时会直接展开函数体,不会调用,即汇编层面不会call
	cout << c << endl;
	return 0;
}

        在调用Add_int()函数时,在汇编层面不会执行call指令,而是直接将形参值相加并返回赋值。

2. 缺省函数

        缺省函数是指在定义函数时为形参指定缺省值(即默认值)

a. 定义方式

        在定义缺省函数时,需注意从右至左依次给出缺省值,具体如下所示

// 可全为缺省参数
void fun_1(int a = 1, int b = 2, int c = 3,int d = 4)
{
	cout << a << b << c << d << endl;
}

// 部分为缺省参数,此情况符合要求
void fun_2(int a, int b = 2, int c = 3,int d = 4)
{
	cout << a << b << c << d << endl;
}

// 部分为缺省参数,此情况不符合要求,无法编译通过
void fun_3(int a = 1, int b, int c = 3,int d = 4)
{
	cout << a << b << c << d << endl;
}

b. 使用方式

        调用缺省参数时,需从左至右依次给出实参,不可跳跃给出,如下所示

void fun(int a = 1, int b = 2, int c = 3,int d = 4)
{
	cout << a << b << c << d << endl;
}

int main()
{
	fun(1, 2, 3, 4);
	fun(1, 2, 3);
	fun(1, 2);
	fun(1);
	fun();
    // fun(1,  , 3, 4);    // 此调用方式错误
	return 0;
}

c. 注意事项

        在多文件项目中,在声明中给出缺省值,在定义中不要给出缺省值;

        另外缺省值可以为常量,也可以是其他函数返回值;

        仅在C++中支持缺省函数

3. 函数重载

        Tips:仅在C++中支持函数重载,C语言中不支持函数重载。

        在C++中可以为两个或两个以上的函数提供相同的函数名称,只要参数类型不同,或者参数类型相同而参数个数不同,即为函数重载。

        在C/C++函数在内部(编译和链接)通过修饰名识别,修饰名是指编译器在编译函数定义或者原型时生成的字符串。在C语言的编译过程中,对于函数编译时,仅在函数名前添加"_"作为修饰名,而在C++编译过程中,在函数编译时,修饰名格式比较复杂,会根据形参列表进行生成,可参考C++标准。也可强制名称修饰方式,即修改默认的修饰名生成方式。

 a. 定义方式

        如下函数my_max()分别为整形、字符型、double类型的两个参数取最大值。

// 整形最大值
int my_max(int a, int b)
{
    return a > b ? a : b;
}
// 字符型最大值
char my_max(char a, char b)
{
    return a > b ? a : b;
}
// double类型最大值
double my_max(double a, double b)
{
    return a > b ? a : b;
}

        在实际情况中,情况可能更为复杂,需根据实际情况进行定义

 b. 调用方式

        在调用时,需与形参列表相对应,程序会调用相应的重载函数

int main()
{
    my_max(12, 23);        // 调用整形重载
    my_max('a', 'u');      // 调用字符型重载
    my_max(12.23, 23.21);  // 调用double重载
    return 0;
}

 c. 注意事项

        1. 如果两个函数的参数表相同,但返回值不同,会被标记为编译错误:函数的重复声明。即定义重载函数时,要注意同一形参列表的函数有且仅有一个。

        2. 参数表的比较过程与形参名无关

        3. 参数表是否给出缺省值与重载无关,即两个相同参数表中,一个给出缺省值,另外一个未给出缺省值,也会被标记为编译错误:函数的重复声明。

        4. typedef的影响,typedef作用是为已有的参数类型创建新名称(马甲),即

typedef unsigned int u_int

unsigned int a;
u_int b;
// a和b是同一种类型的变量,即unsigned int

        5. const和volatile的影响,形参表中若对同一类型的参数一个添加const或volatile修饰符,也不会构成函数重载,即在重载函数声明及定义时,若形参是按值传递方式定义不考虑const和volatile修饰符;若形参为指针或引用的传递,此时const修饰符会影响函数重载,即构成函数重载,但要注意在声明与定义引用类型形参时,需避免普通形参的函数重载,此类情况会造成编译错误,即在声明与定义第二种重载方式时,避免第一种函数重载。

// void print(int a)    {}
void print(int &b)    {}
void print(const int& c)    {}

        但在实际情况中,虽然第二、三种函数重载方式共存时不会造成编译错误,但在实际调用时,第三种重载方式可兼容第二种函数重载,即即使不声明与定义第二种重载方式,仅有第三种重载方式,也可实现第一、二种函数调用的功能,总结为const修饰符的向下兼容性。

        6. 重载函数调用的二义性,如下所示

void func(int a)
{
}
void func(int a, int b = 10)
{
}

int main()
{
    // func(1);    // error
    func(1, 2);
    return 0;
}

        如上代码中,在主函数中的func(1)调用时,会产生二义性,即程序无法确定匹配一个参数的函数还是带缺省值的函数,即会编译错误。因此在函数重载的声明与定义时,尽可能的避免缺省值的添加。

        7. 尽可能的避免相同形参个数,但不同类型的顺序不同方式的函数重载声明与定义,即

void print(int a, char ch)
{
}
void print(char ch, int a)
{
}

 d. 重载解析步骤

        1. 确定函数调用考虑的重载函数的集合,确定函数调用中实参表的属性;

        2. 从重载函数集合中选择函数,该函数可以在(给出实参个数和类型)的情况下可以调用函数;

        3. 选择并调用最匹配的和函数。

4. 函数模板

        为了代码重用,代码就必须是通用的;通用的代码就必须不受数据类型的限制。因此将数据类型改为一个设计参数。这种类型的程序设计成为参数化程序设计。软件模板由模板template构造。包括函数模板function template类模板class template

        函数模板可以用来创建一个通用函数的功能,以支持多种不同形参,简化重载函数的设计。

 a. 定义方式

tempalte<模板参数表>
返回类型 函数名(形式参数表)
{
    // 函数体
}

        其中模板参数表不能为空,尖括号中不能为空,参数可以有多个,用逗号分开。

对上述重载函数的模板设计,如下所示

template <class T>
T my_max(T a, T b)
{
    return a > b ? a : b;
}

 b. 调用方式

        在调用时,仅需成功匹配形参个数,即可调用该模板。

int main()
{
    int x = my_max(12, 23);
    char ch = my_max('a', 'x');
    double dx = my_max(12.23, 34.56);
    return 0;
}

        在调用时,系统会根据实参类型自动生成相应的函数(比如在第一次调用时,会自动生成代码:typedef int T),从而进行调用。

 c. 注意事项

        在实际调用时,实参应为相同类型的参数,或者在调用时如下

int x = my_max<int>(12, 'b');

        即在函数名后添加"<类型名>"强制以该类型生成函数。

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libtorch是一个用于C++的开源机器学习库,它是PyTorch框架的C++前端,可以在不依赖Python环境的情况下使用PyTorch的功能。它提供了一些用于构建、训练和部署深度学习模型的工具和接口。 MobileNet是一种轻量级的卷积神经网络模型,专门设计用于在移动设备和嵌入式系统上进行实时图像分类和目标检测。MobileNet_v2是对MobileNet的改进版本,通过引入更多的深度可分离卷积和倒残差结构,提高了模型的性能和效率。 使用libtorch和MobileNet_v2,我们可以在C++环境中构建、训练和部署目标检测或图像分类模型。首先,我们可以使用libtorch提供的工具将MobileNet_v2的模型定义加载到C++程序中。然后,我们可以使用该模型进行推理,对输入图像进行分类或目标检测,并获取相应的输出结果。 在使用libtorch和MobileNet_v2时,需要注意以下几点:首先,我们需要确保在环境中正确配置了libtorch库,并将其链接到我们的C++程序中。其次,我们可以根据具体的任务需求,使用MobileNet_v2的预训练模型或根据自己的数据集进行训练和微调。最后,我们可以使用libtorch提供的接口进行模型的推理和结果的处理。 总而言之,libtorch和MobileNet_v2的结合可以提供一个在C++环境中进行目标检测和图像分类的解决方案,使得我们可以在移动设备或嵌入式系统中部署高性能且轻量级的深度学习模型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值