C++ primer阅读笔记----------------函数

该博客用于记录自己在阅读过程中不懂的知识点,很少用到但比较重要的知识点以及模棱两可的知识点

只存在与函数执行期间打对象叫自动对象,与之对应的是局部静态对象


传参时可以只用引用避免拷贝,拷贝大的对象效率低而且有些类类型不支持拷贝,使用引用还可以返回额外信息


实参初始化形参时会忽略顶层const,这就意味着

    void func(const int i);

    void func(int i);

并不是重载函数,会报出重复定义动错误,第一个func既可以传入constint也可以传入 intfunc并不能向i写值。


形参的初始化和变量的初始化是一样的


voidprint(const int[10]); //这里的10只是我们的期望值,实际上不一定,因为传入的实际上是指针为了限制数组的规格,我们一般采用3

种方法:

    1.使用标记//’\0’

    2.使用标准库规范//beginend指针

    3.显式的传入一个表示数组规格的形参


如果数组不需要写操作,我们一般把数组形参写成指向const的指针


我们也可以把形参写成数组动引用,此时需要带上数组动规格, 例:

    void print(int (&arr)[10]){
        /*

        *

        */

    }

但这样写无疑是限制例我们只能将函数作用于大小为10的数组


二维数组的形参定义

    void print(int ( *matrix) [10] ){}

    void print(int matrix[][10]){} //等价


main函数处理命令行选项 :

   

aegc 是一个int型变量用于表示argv字符数组中的字符串数量,举个例子帮助理解

    prog-d -o ofile data0

    argv[0]= “prog”;

    argv[1]= “-d”;

    argv[2]= “-o”;

    argv[3]= “ofile”;

    argv[4[= “data0”;

    argv[5]= 0;


含有可变形参的函数

    形参类型相同时:initializer_listvector类似,不一样的是这个对象中的元素永远是常量

    .size()表示对象中的元素数量

    .begin().end()首尾指针

   

    值得一提的是initializer_list对象之间赋值时不会拷贝列表中的元素/*list2(list)*/ /*list2=lsit*/拷贝完成后原始列表和副本共享元素

   

    传参时不仅可以传initializer_list对象也可以传一对花括号包裹的值序列

   

    当形参类型不同时我们可以编写一种特殊的函数,也就是所谓的可变参数模板(后面再提)



省略符形参是为了方便C++程序访问某些特殊的C代码而设定的,这些代码使用了名为varargsC标准库功能。通常省略符形参不应

该用与其他目地。


函数返回一个值的方式和初始化一个变量或形参的方式完全一样

返回类型为引用的函数得到左值,其他类型得到右值,可以像正常左值一样使用返回函数的引用的调用

/*func(a).size */     //func是一个返回非常量引用的函数

也可以对返回非常量引用的函数的结果赋值

/*func(a) = “asda” */



函数也可以返回花括号包裹的值列表

vector <string> func(){

    return{“a”, “bb”, “ccc”};

}


main函数的返回值并不是void,返回0表示执行成功,如果结尾没有return语句,编译器会隐式的插入一条return0;返回非0值表示执行失

败,具体含义由机器决定,为了使返回值与机器无关。cstdlib定义了两个预处理变量(由预处理器定义,不能加std,也不能加using)

    return EXIT_FAILURE;

    return EXIT_SUCCESS;


返回一个数组的指针或引用的函数比较繁琐,常用别名来简化操作

    typedef int arr[10];

    using arr = int[10]; //arr是 类型为10个整数的数组的别名

    arr* func(int i); //返回值是一个指向含有10个整数的数组的指针


不用别名声明一个返回数组指针的函数

    int (*p)[10] = &arr; //p2是一个指针,它指向含有10个整数的数组

我们可以从上面得到启发,不使用别名:

    int ( *func ( int i) ) [10];


使用尾置返回类型依然可以简化上述操作

    auto func(int I) -> int(*)[10];


也可以使用decltype

    int odd[] = {1, 3, 5, 7, 9}; //odd是一个含有5个整型元素的数组

    decltype(odd) *func(int I);



函数重载时顶层const的有无是等价的,会导致重复定义

    int func(int i);

    int func(const int i);

    int func(int *i);

    int func(int *const I);

底层const可以构成重载

    int func(int &i);

    int func(const int &i);


    int func(int *i);

    int func(const int *i);



const_cast和重载,填前面的坑

    const string &shortStr(cosnt string &s1, const string &s2){

        returns1.size() <= s2.size() ? s1 : s2;

    }

然而虽然该函数可以传进 常量和非常量 引用,但它返回的结果是常量引用


所以我们可以写一个重载函数将形参定为非常量引用,再用一个常量引用的副本接受上面那个函数的返回值(其中形参可以通过

const_cast转换为常量引用),然后在返回的时候再转换为非常量引用

string& shortStr(string &s1, string &s2){

    auto &r = shortStr(const_cast<const string&> (s1),const_cast<const string&>(s2));

    return const_cast<string &>(r);

}



当一个函数多次声明时,后续声明不能修改前面声明的默认实参,并且要保证右边的形参全部都有默认实参


constexpr函数可以作用于常量表达式,但其返回值和形参都必须是字面值类型且只有一个return语句,概括的说cosntexpr函数在编译期

间就必须能够知道函数的所有信息,constexpr函数被隐式的指定为内联函数,因为在编译的时候编译器就要将内联函数展开,所有内

联函数的声明和定义一般都写在头文件中


为了帮助调试程序,产生例许多帮助调试的东西

1.assert(expr)这是一种预处理宏,由预处理器管理,如果expr表达式为0则终止程序执行,如果为假则什么也不做。和其他预处理变量

一样,使用它不需要std::using

assert预处理宏的执行依赖于一NDEBUG预处理变量的定义,如果定义了NDEBUG,则表示关闭例调试状态,无论expr表达式是什么

assert都不执行

因为NDEBUG的定义用到的是#define,所以,我们可以灵活使用它,而不仅仅局限于使用assert函数,比如我们可以像条件编译一样

使用它:

#ifndef NDEBUG

/*

*此处可以写自己的调试代码

*/

#endif

编译器还定义了一个__func__变量用于表示当前函数的名字,除此之外预处理器也定义了4个预处理变量:

__FILE__存放文件名的字符串字面值;

__LINE__存放当前行号的整型字面值;

__TIME__存放文件编译的时间的字符串字面值

__DATE__存放文件编译日期的字符串字面值


当调用一个函数传入的实参可以和多个重载函数匹配,并且难以判断孰优孰劣,则函数调用会产生二义性,编译器会拒绝这个请求,例:

            void func(int i, int j);

            void func(double i, double j);

当调用时,func(1,1.2),对于第一个实参1,第一个函数更匹配,对于第二个实参1.2,第二个函数更匹配,则不能比较出调用谁更合适

(虽然可以相互转换),则会产生二义性


既然编译器会比较谁更匹配,那么必然就有一个标准来决定匹配的优先级:

1.精确匹配:

    实参和形参类型完全相同

    从数组类型或函数类型(函数指针)转换为指针类型

    顶层const的转换

2.底层const间的转换实现的匹配

3.整型提升实现的匹配

4.算术转换或指针转换实现的匹配

5.类类型转换实现的匹配


整型提升的过程中,并不少就近原则,所有小整型都会提升为int,如

void func(int);

void func(short);

func(‘a’); //将会提升为int调用第一个,如果想调用第二个反而会导致类型转换,这里要提一下, char是一种特殊的整型


所有类型转换的优先级都一样,如:

void func(long);

void func(float);

func(3.14); //将会产生二义性,因为都发生了类型转换,值得一提的是3.14默认是double类型的,3.14f才是float类型的



函数指针:

函数声明:bool func(const string &, const string &);


该函数类型的指针bool (*p)(const string &, const string &); //函数类型由返回值和形参类型决定,该指针未初始化


bool *p(const string &, const string &); //括号必须带上,否则为返回值为bool类型指针的函数的声明


p= func;

p= &func//两个赋值方法是等价,&可省略


与上面的相同,当使用函数指针时不需要解引用指针

bool p1 = p(“aaa”, “bbb”);

bool p1 = (*p)(“aaa”, “bbb”);

bool p1 = func(“aaa”, “bbb”); //三者等价


函数指针不存在类型转换规则

使用函数指针时,指针类型必须与函数类型精确匹配,意味着就算形参类型可以通过转换得到也不行

void func(unsigned int);

void (*p)(int) = func; //错误,unsigned intint不是精确匹配


与数组相同,形参类型虽然不能是函数类型(也可以写成函数类型,不过会自动转换成指向函数的指针类型),但可以是指向函数的指

针类型

void func(int);

void test(void (*p)(int)); //test的形参是一个函数指针


然而这样写会显得很冗长,类型别名是一个不错的选择:

typedef void (*f)(int);指向形参为1个整型,返回值为void的函数的指针的类型别名为f

typedef decltype(func) *f; //等价


使用类型别名后:

void test(f);


同理,虽然不能返回一个函数,但可以返回一个指针,然而与形参不同的是,函数类型并不会转换成指针类型

using PF = void (*)(int);

using F = void (int);

PF f1(); //正确,PF是指向函数的指针,所有f1的返回值是指向函数的指针

F f1(); //错误,F是函数类型,f1不能返回一个函数

F *f1(); //正确,显式的将返回类型指定为指向函数的指针


没有用到别名的写法: void (*f1())(int);


同样也可以使用decltype简化

int f1(int);

decltype(f1) *returnF1(); //返回值是一个指向f1的指针




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于YOLOv9实现工业布匹缺陷(破洞、污渍)检测系统python源码+详细运行教程+训练好的模型+评估 【使用教程】 一、环境配置 1、建议下载anaconda和pycharm 在anaconda中配置好环境,然后直接导入到pycharm中,在pycharm中运行项目 anaconda和pycharm安装及环境配置参考网上博客,有很多博主介绍 2、在anacodna中安装requirements.txt中的软件包 命令为:pip install -r requirements.txt 或者改成清华源后再执行以上命令,这样安装要快一些 软件包都安装成功后才算成功 3、安装好软件包后,把anaconda中对应的python导入到pycharm中即可(不难,参考网上博客) 二、环境配置好后,开始训练(也可以训练自己数据集) 1、数据集准备 需要准备yolo格式的目标检测数据集,如果不清楚yolo数据集格式,或者有其他数据训练需求,请看博主yolo格式各种数据集集合链接:https://blog.csdn.net/DeepLearning_/article/details/127276492 里面涵盖了上百种yolo数据集,且在不断更新,基本都是实际项目使用。来自于网上收集、实际场景采集制作等,自己使用labelimg标注工具标注的。数据集质量绝对有保证! 本项目所使用的数据集,见csdn该资源下载页面中的介绍栏,里面有对应的下载链接,下载后可直接使用。 2、数据准备好,开始修改配置文件 参考代码中data文件夹下的banana_ripe.yaml,可以自己新建一个不同名称的yaml文件 train:训练集的图片路径 val:验证集的图片路径 names: 0: very-ripe 类别1 1: immature 类别2 2: mid-ripe 类别3 格式按照banana_ripe.yaml照葫芦画瓢就行,不需要过多参考网上的 3、修改train_dual.py中的配置参数,开始训练模型 方式一: 修改点: a.--weights参数,填入'yolov9-s.pt',博主训练的是yolov9-s,根据自己需求可自定义 b.--cfg参数,填入 models/detect/yolov9-c.yaml c.--data参数,填入data/banana_ripe.yaml,可自定义自己的yaml路径 d.--hyp参数,填入hyp.scratch-high.yaml e.--epochs参数,填入100或者200都行,根据自己的数据集可改 f.--batch-size参数,根据自己的电脑性能(显存大小)自定义修改 g.--device参数,一张显卡的话,就填0。没显卡,使用cpu训练,就填cpu h.--close-mosaic参数,填入15 以上修改好,直接pycharm中运行train_dual.py开始训练 方式二: 命令行方式,在pycharm中的终端窗口输入如下命令,可根据自己情况修改参数 官方示例:python train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 训练完会在runs/train文件下生成对应的训练文件及模型,后续测试可以拿来用。 三、测试 1、训练完,测试 修改detect_dual.py中的参数 --weights,改成上面训练得到的best.pt对应的路径 --source,需要测试的数据图片存放的位置,代码中的test_imgs --conf-thres,置信度阈值,自定义修改 --iou-thres,iou阈值,自定义修改 其他默认即可 pycharm中运行detect_dual.py 在runs/detect文件夹下存放检测结果图片或者视频 【特别说明】 *项目内容完全原创,请勿对项目进行外传,或者进行违法等商业行为! 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值