cpp_02_函数重载_动态内存分配_左值右值_引用_内联函数

1  函数重载

1.1  定义

        要求:

        1)同一作用域内

        2)函数名相同

        3)形参表不同(与形参个数及每个形参类型有关,与形参名无关)

        重载关系的函数调用哪个:

        根据实参类型和形参类型进行匹配,调用最匹配的函数

// overload_pre.cpp
// 函数之间的关系--重载关系(1.同一作用域内  2.函数名相同  3.形参表不同)
// 形参表是否相同 与 形参名无关 与 形参的个数 以及 每一个对应形参的类型有关
#include <iostream>
using namespace std;

void foo( char* c, short s ) {
    cout << "1. foo" << endl;
}
void foo( int i, double d ) {
    cout << "2. foo" << endl;
}
void foo( const char* c, short s ) {
    cout << "3. foo" << endl;
}
void foo( double d, int i ) {
    cout << "4. foo" << endl;
}

// int foo( double i, int d ) {} // error-是否为重载关系和返回值类型无关
// void foo( double i, int d ) {} // error-形参表是否相同 与 形参名无关
int main( void ) {
    char* c;    short s;
    foo( c, s ); // 1
    const char* cc;
    foo( cc, s ); // 3
    int i;  double d;
    foo( i, d ); // 2
    foo( d, i ); // 4
    return 0;
}

1.2  重载和隐藏:

        -只有同一作用域内的同名函数才涉及重载的关系

        -不同作用域的同名函数涉及的是隐藏关系(定义表隐藏可见表)

// overload.cpp 详谈同一作用域
#include <iostream>
using namespace std;
namespace ns1 {
    void foo( char* c, short s ) {
        cout << "1. foo" << endl;
    }
    void foo( int i, double d ) {
        cout << "2. foo" << endl;
    }
}
namespace ns2 {
    void foo( const char* c, short s ) {
        cout << "3. foo" << endl;
    }
    void foo( double d, int i ) {
        cout << "4. foo" << endl;
    }
}
int main( void ) {
    using ns2::foo; //名字空间声明,从这行代码开始ns2中foo引入当前作用域(出现在定义表中)
    using namespace ns1;//名字空间指令,从这行代码开始ns1中的foo在当前作用域可见(出现在可见表中)
    char* c;    short s;   
    foo( c, s ); // 第3个foo将第1个foo函数隐藏
    return 0;
}

1.3  重载匹配优先级

        1)普通方式调用重载关系的函数:

        完全匹配 > 常量转换 > 升级转换(小转大) > 标准转换(大转小) > 自定义转换 > 省略号匹配

        2)函数指针方式调用重载关系的函数:

        函数指针本身的类型决定其调用哪个版本的重载函数。

        工作中建议完全匹配。

// overload2.cpp 重载匹配优先级
#include <iostream>
using namespace std;

void foo( char* c, short s ) { // _Z3fooPcs 完全匹配
    cout << "1. foo(char*, short)" << endl;
}
void foo( const char* c, short s ) { // _Z3fooPKcs 常量转换
    cout << "2. foo(const char*, short)" << endl;
}
void foo( char* c, int s ) { // _Z3fooPci 升级转换(小转大,没有数据损失)
    cout << "3. foo(char*,int)" << endl;
}
void foo( char* c, char s ) { // _Z3fooPcc 标准转换(大转小,可能数据损失)
    cout << "4. foo(char*,char)" << endl;
}
void foo( ... ) { // _Z3fooz 省略号(可变长)匹配
    cout << "5. foo(...)" << endl;
}
int main( void ) {
    char * c;   short s;
    foo( c,s ); //_Z3fooPcs(c,s) 
    // 普通方式调用重载关系的函数,根据实参类型和形参类型匹配,来确定调用哪个foo

    void(*pfunc)(const char*,short) = foo; // _Z3fooPKcs  定义函数指针,形参可无名
    pfunc(c,s); // 函数指针方式调用重载关系的函数,
                // 根据函数指针本身的类型,来确定调用哪个foo
    return 0;
}

        注意上述代码,定义函数指针,可以不写形参名。 

1.4  重载揭秘

        重载是通过C++换名机制来实现的:

        nm a.out 命令 查看函数符号名

        

        通过extern  "C" 可以要求C++编译器按照C方式编译函数,即不做换名,当然也就无法重载

// extern/cal.cpp
extern "C" {                      //extern "C" {} ,缩不缩进都可
    int add( int a, int b ) {
        return a + b;
    }

    int sub( int a, int b ) {
        return a - b;
    }
}
// extern/main.c
#include <stdio.h>

int main( void ) {
    int c = add( 5, 3 );
    int d = sub( 5, 3 );
    printf("c=%d,d=%d\n", c, d);
    return 0;
}
//g++ -c cal.cpp  
//nm cal.o  //由于extern "C",函数没换名,与c代码中一致
//gcc -c main.c
//nm main.o
//gcc main.o cal.o  
//./a.out

2  动态内存(堆内存)分配

        可以继续使用标准C库函数malloc()/free(),

        free(野指针)后果很严重(段错误,double free),free(空指针)安全:

// new.cpp 动态(堆)内存分配
#include <iostream>
#include <cstdlib>
using namespace std;

int main( void ) {
    int* pm = (int*)malloc( 4 );
    cout << "*pm=" << *pm << endl; // 初始值为0
    free( pm ); // 当这行代码执行结束后,pm指向的堆内存被释放,进而pm变为野指针
    pm = NULL;  // pm变为空指针
    free( pm ); // 给free传递的为野指针,释放野指针后果很严重,释放空指针是安全
    return 0;
}

        更建议使用new/delete操作符在堆中分配/释放内存:

                int*  pi  =  new  int;         //初始值一般为0

                delete  pi;

        在分配内存的同时初始化

                int*  pi  =  new  int( 100 );   //初始值为100

        可以数组方式new:

                int*  pi  =  new  int [4] {10, 20, 30, 40};  // {}方式是11标准才支持的,编译时-std=c++11

                想申请16字节,实际多申请4字节,存储数组元素的个数

        但也要数组方式delete:

                delete[]  pi;                            加[],才能将多申请的4字节也释放掉

        通过new操作符分配N维数组,返回N-1维数组指针

                int (*pa) [4] = new int [3][4];  // 返回值类型是 int (*)[4]

                int (*pb) [4][5] = new int [3][4][5];  // 返回值类型是 int (*)[4][5]

        不能通过delete操作符释放已释放过的内存。

        delete野指针后果很严重(段错误,double free),delete空指针安全。

        故建议释放指针指向的内存后,立即置空:   

                delete(pn);     

                pn = NULL;

        new操作符申请内存失败,将抛出异常 。

// new.cpp 动态(堆)内存分配
#include <iostream>
#include <cstdlib>
using namespace std;

int main( void ) {
    int* pm = (int*)malloc( 4 );
    cout << "*pm=" << *pm << endl; // 初始值为0
    free( pm ); // 当这行代码执行结束后,pm指向的堆内存被释放,进而pm变为野指针
    pm = NULL;
    free( pm ); // 给free传递的为野指针,释放野指针后果很严重,释放空指针是安全

    int* pn = new int(100);
    cout << "*pn=" << *pn << endl; // 可以自己指定初始值为100
    delete pn; // 当这行代码执行结束后, pn指向的堆内存被释放,进而pn变为野指针
    pn = NULL;
    delete pn; // 给delete传递野指针,释放野指针后果很严重,释放空指针是安全

    int* parr = new int[4]{10,20,30,40};//以数组方式new一块内存,永远返回第1个元素的地址
    for( int i=0; i<4; i++ ) {
        cout << parr[i] << ' ';
    }
    cout << endl;
    delete[] parr; // 数组方式new的也要以数组方式delete

    // 不管是几维数组,都应该当做一维数组看待
    int(*p)[4] = new int[3][4]; // 返回值是一维数组类型的指针
    delete[] p;

    try {
        new int[0xFFFFFFFF];
    }
    catch(...) {  //捕获...
    
    }
    return 0;
}
//g++ new.cpp -std=c++11

3  左值和右值

        C++所有数据,不是左值,就是右值:

        左值:能够取地址的值,通常具名

        右值:不能取地址的值,通常匿名

// lrvalue.cpp 左值 和 右值
#include <iostream>
using namespace std;

int foo( ) {
    int m=888;
    return m;
}

int main( void ) {
// 当前作用域的生命期
// 具名内存-->能够取址-->左值|非常左值(无const修饰)
//                           |常左值  (有const修饰)
    int a = 10;
    &a;
    a = 15;

    const int b = 10;
    &b;
//  b = 15; // error

// 语句级生命期
// 匿名内存-->不能取址-->右值|直接更改右值毫无意义(98/03标准给出结论)
//
    10;
//  &10; // error
//  10 = 15; // error

    /*|888|*/foo( ); // (1)分配一块内存空间  (2)生成跳转指令
//  &foo( ); // error
//  foo( ) = 15; // error
    return 0;
}

4  引用(如影随形,从一而终)

        1)引用即内存的别名

                int  a = 10;  // a是内存的真名

                int&  b = a;  // 不是赋值,而是给a起别名!(给引用b,赋真名)

        2)C++层面,引用本身不占内存并非实体

              对引用(别名)的所有操作都是在对目标内存进行操作。

        3)引用必须初始化,且不能更换目标

                int  c = 20;

                b = c;  // 仅仅是对引用的目标内存a进行赋值

        4)不存在引用的引用

                int  a = 10;

                int&  b = a;   //别名b,真名a

                int&  d = b;   //别名d,真名a

        5)引用的常属性必须和目标的常属性“一致” 

                const  int  e = 10;

                const  int&  f = e;   // OK

                int&  g = e;   // ERROR

        6)可以限定更加严格

                int  a = 10;

                const int& h = a; // OK

// alias.cpp 引用:就是一块内存的别名
#include <iostream>
using namespace std;

int main( void ) {
    int a = 10;
    int& b = a; // 这并不是利用a的数据给b赋值,而应该理解为 引用b是a所代表内存的别名

    b = 20; // 对 引用b赋值,其实就是在对引用b的目标内存(a)赋值
    cout << "a=" << a << ", b=" << b << endl;//读取引用b的值,
                                             //其实读取的为引用b的目标内存(a)的值
    cout << "&a:" << &a << ", &b:" << &b << endl;
    // 取引用b的地址,其实取的为引用b的目标内存(a)的地址
    
    int c = 30;
    b = c;
    cout << "a=" << a << ", b=" << b << ", c=" << c << endl;
    cout << "&a:" << &a << ", &b:" << &b << ", &c:" << &c << endl;

    return 0;
}

        7)引用可以延长右值的生命周期 

        8)常引用  即  万能引用 

// alias2.cpp 

5  内联函数

        调用普通函数(非内联函数)的问题:

        -每个普通函数调用语句都需要发生跳转操作,这种跳转操作会带来时间开销

                

        内联就是用函数已被编译好的二进制代码,替换对该函数的调用指令。

        内联在保证函数特性的同时,避免了函数调用的时间开销

                

// inline.cpp 内联函数:编译器的优化策略 
#include <iostream>
using namespace std;

void foo( int x ) { // 非内联(普通)函数
    cout << "foo(int): " << x << endl;
}

inline void bar( int x ) { // 内联函数
    cout << "bar(int): " << x << endl;
}

int main( void ) {
    
    foo( 10 ); // 将此处替换为 跳转指令
    foo( 20 ); // ...
    foo( 30 ); // ...
    bar( 10 ); // 见此处替换为 bar函数编译后产生的二进制指令集
    bar( 20 ); // ... 
    bar( 30 ); // ...
    return 0;
}

        内联会使文件的体积变大,进而导致进程的内存变大,因此只有频繁调用简单函数才适合内联。

        稀少被调用的复杂函数递归函数都不适合内联。

        inline关键字仅表示期望该函数被优化为内联,但是否适合内联则完全由编译器决定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/252119.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

降采样方法对NCC得分的影响因素评估

定位算法原理 关于不同的定位场景,最适合使用的算法原理,Halcon的原理文档中描述如下: 在图案缩放可用忽略,图案纹理丰富的场景,适合采用基于互相关的匹配。 输入参考图像,搜索图像,参考图像在搜索图像上滑动,得到滑动位置的NCC得分。如下图所示,高于阈值的最亮的地…

基于循环神经网络长短时记忆(RNN-LSTM)的大豆土壤水分预测模型的建立

Development of a Soil Moisture Prediction Model Based on Recurrent Neural Network Long Short-Term Memory in Soybean Cultivation 1、介绍2、方法2.1 数据获取2.2.用于预测土壤湿度的 LSTM 模型2.3.土壤水分预测的RNN-LSTM模型的建立条件2.4.预测土壤水分的RNN-LSTM模型…

后端项目-自定义接口响应结果设计JsonResult

文章接上文&#xff1a;后端接口增删改查 上文中返回的值是string格式&#xff0c;明显是不合适。 一般情况下&#xff0c;我们返回给前台的都是对象格式&#xff0c;结合添加在类上添加RestController注解&#xff0c;标记此类中所以的处理请求的方法都是响应正文的&#xff…

dp中最短编辑距离的笔记(分析dp)

dp分析往往就是看最后一步的变化。 分析&#xff1a; 设a串长度为i&#xff0c;b串长度为j。题目要求为通过三种操作将a字符串转化为b字符串的最少次数。 删除操作&#xff1a; 把a[i]删除后a[1~i]和b[1~j]匹配&#xff0c;所以可以得到f[i - 1][j] 1&#xff0c;在此之前要先…

Crocoddyl: 多接触最优控制的高效多功能框架

系列文章目录 前言 我们介绍了 Crocoddyl&#xff08;Contact RObot COntrol by Differential DYnamic Library&#xff09;&#xff0c;这是一个专为高效多触点优化控制&#xff08;multi-contact optimal control&#xff09;而定制的开源框架。Crocoddyl 可高效计算给定预定…

java minio通过getPresignedObjectUrl设置(自定义)预签名URL下载文件的响应文件名之minio源码改造方案

Minio预签名URL自定义响应文件名之Minio源码改造 需求说明Minio源码改造一、环境准备二、下载Minio源代码三、修改源代码1.修改cmd目录下的api-router.go这个代码文件2.将filename参数值设置到响应头4.修改验证签名时是否需要带入filename参数验证 四、大功告成&#xff0c;编译…

外包干了一个月,技术有明显提升。。。。。

先说一下自己的情况&#xff0c;本科生生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试…

百度地图中显示红点

initMap(longitude, latitude) {var map new BMapGL.Map("container");// 创建地图实例if (longitude null || latitude null) {var point new BMapGL.Point(111.1480354849708, 37.5262978563336);var marker new BMapGL.Marker(point);map.addOverlay(marker)…

003 Windows用户与组管理

Windows用户管理 一、用户账户 1、什么是用户账户 不同用户身份拥有不同的权限每个用户包含了一个名称和一个密码每个用户账户具有唯一的安全标识符查看系统中的用户 net user 安全标识符&#xff08;SID&#xff09; whoami /user 使用注册表查看 打开注册表命令regedi…

visual studio 2019 移除/卸载项目已经如何再加载项目

文章目录 移除解决方案下的某个项目添加已移除的项目移除项目加载已卸载的项目注意事项 移除解决方案下的某个项目 在项目名称上&#xff0c;点击鼠标右键&#xff0c;弹出右键工具栏&#xff0c;找到 移除 功能。 然后鼠标左键点击 移除。 弹出的模态框&#xff0c;选择确定…

深度学习记录--随机初始化

权重 权重&#xff0c;指的是变量系数w&#xff0c;决定了变量的变化率 它会改变dw&#xff0c;进而改变下一轮的w(改变更新) 神经网络的权重 对于神经网络(含隐藏层) 由于权重的对称性&#xff0c;我们的隐层的神经单元输出始终不变&#xff0c;出现隐藏神经元的对称性 …

代码随想录刷题题Day15

刷题的第十五天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day15 任务 ● 513.找树左下角的值 ● 112. 路径总和 113.路径总和ii ● 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历…

创建conan包-打包方法

创建conan包-打包方法 1 1 config (1 build) -> 1 package2 N configs -> 1 package2.1 Warning2.2 N configs -> 1 package2.3 N - 1 示例代码2.4 创建N - 1示例包2.5 Important 3 N configs (1 build) -> N packages 本文是基于对conan官方文档Packaging Approac…

Qlik Sense 之什么是Dimensions维度和Measures度量

Dimensions 维度 | Windows 版 Qlik Sense帮助https://help.qlik.com/zh-CN/sense/May2023/Subsystems/Hub/Content/Sense_Hub/Dimensions/dimensions.htm Dimensions determine how the data in a visualization is grouped. For example: total sales per country or numbe…

微服务实战系列之ZooKeeper(下)

前言 通过前序两篇关于ZooKeeper的介绍和总结&#xff0c;我们可以大致理解了它是什么&#xff0c;它有哪些重要组成部分。 今天&#xff0c;博主特别介绍一下ZooKeeper的一个核心应用场景&#xff1a;分布式锁。 应用ZooKeeper Q&#xff1a;什么是分布式锁 首先了解一下&…

基于注解管理Bean --@Resource注入

基于注解管理Bean --Resource注入 Resource注解也可以完成属性注入。那它和Autowired注解有什么区别&#xff1f; Resource注解是JDK扩展包中的&#xff0c;也就是说属于JDK的一部分。所以该注解是标准注解&#xff0c;更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Ja…

C# WPF上位机开发(树形控件在地图软件中的应用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们聊过图形软件的开发方法。实际上&#xff0c;对于绘制的图形&#xff0c;我们一般还会用树形控件管理一下。举个例子&#xff0c;一个地图…

使用java获取nvidia显卡信息

前言 AI开发通常使用到GPU&#xff0c;但通常使用的是python、c等语言&#xff0c;java用的则非常少。这也导致了java在gpu相关的库比较少。现在的需求是要获取nvidia显卡的使用情况&#xff0c;如剩余显存。这里给出两种较简单的解决方案。 基于nivdia-smi工具 显卡是硬件&a…

如何让.NET应用使用更大的内存

我一直在思考为何Redis这种应用就能独占那么大的内存空间而我开发的应用为何只有4GB大小左右&#xff0c;在此基础上也问了一些大佬&#xff0c;最终还是验证下自己的猜测。 操作系统限制 主要为32位操作系统和64位操作系统。 每个进程自身还分为了用户进程空间和内核进程空…

数码管的动态显示

说到动态显示&#xff0c;我们可以说是轻车熟路了&#xff0c;之前的LED已经练过不少了&#xff0c;此次只是把LED换成了数码管&#xff0c;原理一样&#xff0c;还是一样的电路&#xff0c;接下来看看如何做到动态显示。 首先是对程序代码做些更改&#xff0c;只要要加上扫描的…