当前位置: 首页 > news >正文

猿创征文 |【C++】C向C++知识的过度(下)

文章目录

  • 前言
  • 一、C与C++中的&取址符
    • 1.1 C中的&取址符回顾与拓展
    • 1.2 C++中的&取址符
  • 二、C与C++中的const修饰符
    • 2.1 C中的const修饰符回顾与拓展
    • 2.2 C++中const的用法
  • 三、C++中内联函数
    • 3.1 C中宏函数
    • 3.2 C++中的内联函数 inline
    • 3.3 C++中内联函数和带参宏有什么区别?
  • 四、C++中函数的默认参数
  • 五、C++中函数重载机制
  • 六、哑元

前言

承接上文C向C++知识的过度(上)感兴趣可以了解一下。

一、C与C++中的&取址符

1.1 C中的&取址符回顾与拓展

普通用法:p指针变量保存了a变量的地址。

int a=10;
int *p=&a;

一维数组与指针的用法:

int arr[3] = {1,2,3};
int* parr = arr;

数组指针用法:如果是数组指针移动+1 移动整个数组的大小。

int(* parr2)[3] = &arr;

函数指针用法:my_func前面的&可有可无。
在这里插入图片描述

1.2 C++中的&取址符

在C++面向对象中,我们多一种函数,叫做成员函数
成员函数指针的调用与成员函数的调用是一样,也是依赖于结构体对象(变量)的调用。

使用成员函数指针,调用成员函数的方法如下:

#include <iostream>
using namespace std;
struct Stu
{
    string name;
    int age;
    void write_code()
    {
        cout << "正在努力地写代码" << endl;
    }
};
int main()
{
    void (Stu::*pfun)() = &Stu::write_code;
    Stu stu;
    (stu.*pfun)();
    return 0;
}

&在成员函数中,取址的方式的用法。指向此函数地址的函数指针。
在这里插入图片描述

二、C与C++中的const修饰符

2.1 C中的const修饰符回顾与拓展

const修饰的变量叫做只读变量。这个变量的值是不可以修改的。
但是它终究还是个变量。

const在C的一些用法:

#include <stdio.h>
int main()
{
    const int a = 10;
    //a = 100;错误的,不能通过只读变量修改变量中的值。

	//在C中const修饰的这种只读变量,是可以通过指针的方式进行修改的。
    int* p = &a;
    *p = 10000;
    printf("%d \n",a);//打印10000
    int arr[a] = {0};
    //不能做为定义数组的长度使用。
    //这种使用只读变量去定义数组的方式是错误的。
    return 0;
}

const关于指针用法回顾:

#include <iostream>
using namespace std;
int main()
{
    int a = 100;
    const int* p = &a; 
    //const修饰是谁? int* 这个指针的类型。
    //指针有三种属性:读操作,写操作,移动
    //*p = 1000;//*操作就没有写的属性,所以不可以通过*的方式向内存写数据。
    int c = 500;
    p = &c;//这种方法是可以实现的
    
    int const* p1 = &a; //修饰的int*,与上面的效果是一样的。
    //*p1 = 1000;这是错误的。
    
    int d = 1000;
    int* const p2 = &d;//此时const修饰的是p2,p2是指针变量。
    *p2 = 5000;//p2中保存这个地址是不可以改变。
    //p2 = &a;//这是不对的。            
    return 0;
}

2.2 C++中const的用法

#define MAX 1024

官方推荐 当定义宏时在C++中推荐const修饰的方式来替换宏定义。

const int my_max = 1024;

使用这种方式更加安全可靠。
因为C++是面向大型程序的,所以要更严谨一些。

C++中的const修饰符:

#include <iostream>
using namespace std;

int main()
{
    const int a=10;
    int *p=(int*)&a;
    *p=60;
    cout << a << endl;
    cout << *p << endl;
    return 0;
}

在这里插入图片描述
为什么在C++中a还是10,并没有被改变呢?
这与我们的C++编译器优化有关。

这个a的10,在再次使用的时候,编译器没有从这个地址中去取值。
当const修饰这个变量如果是一个立即数时,编译器会把这个值直接放在寄存器中,在程序中如果出现a这个变量时,编译器直接把a以一个立即数的方式直接替换。我们的编译器是直接从寄存器上取的值。

我们把这个const修饰的变量承接是立即数的变量,也叫做符号常量。他在使用时,编译器是直接在寄存器中取这个值。

意义:程序的运行的高效性。

如果想要获取a中的值的话,就让编译器老老实实去a的址中去取址,使用volatile进行修饰,或者以下面这种方式

int b=10;
const int a=b;//只读变量

当const修饰的变量承接的立即数时,就可以完全视之为一个常量使用。

三、C++中内联函数

C++内联函数就是用来提高代码运行效率的,主要用于继承C中宏函数的高效的特性,同时又避免宏函数所出现的莫名的Bug
但也是有代价的,因为他是直接展开,所以最终会造成可执行程序的代码的膨胀。

3.1 C中宏函数

以下MAX(a,b)就是一个宏函数

#include <stdio.h>
#define MAX(a,b) a>b?a:b
int main()
{
    int x=10;
    int y=20;
    printf("%d",MAX(x,y));
    return 0;
}

3.2 C++中的内联函数 inline

函数定义前加inline,就是说建议编译器把这个函数进行内联。
内联函数既保障了代码运行的高效性,同时也避免了宏函数Bug的存在。
但是内联函数是有代价的:
只能使用代码简短的,且没有循环,没有耗时操作的函数才可以内联,内联函数不可以有递归。
内联函数的代价:最终可执行代码的膨胀。

普通函数的调用过程:
调用完之后,就不存在了,所以最终的可执行程序的代码量不会膨胀。

#include <iostream>
using namespace std;

inline int max(int a,int b)
{
    return a>b?a:b;
}
int main()
{
    int a=10;
    int b=20;
    cout << max(a,b) << endl;
    return 0;
}

3.3 C++中内联函数和带参宏有什么区别?

  1. 宏定义的替换是在预处理阶段完成的,内联函数是在编译阶段完成的;
  2. 内联函数也是函数,和函数的使用方式一样,也会做类型的检查,而宏定义只是能完成简单的替换。

四、C++中函数的默认参数

C++函数的参数是可以设定默认值,设定默认值的方式被认为是C++函数使用的一种灵活性的体现。

  1. C语言中函数的形参的值必须由实参传递过来,而C++中可以给函数的形参一个默认值,
    如果有默认值了,实参传了,就用实参的值。
    实参没传,就用默认值。
  2. 因为函数传参遵循的靠左原则,所以给定默认参数时要遵循靠右原则,否则有歧义,会报错。
    函数参数的入栈过程是依次从右往左进行的,所以函数的默认参数在设定时也要从右往左依次设定,不能跳跃。
  3. 默认参数只能写在函数声明处,不能写在定义处。因为函数调用时,优先看到的是声明。
#include <iostream>
using namespace std;

int add(int a,int b,int c=10)
{
    return a+b+c;
}
int main()
{
    int a=10;
    int b=20;
    cout << add(a,b) << endl;//输出40
    return 0;
}

结果展示:
在这里插入图片描述

五、C++中函数重载机制

第一种静态多态的机制
多态:即同名函数实现的不同的形式(执行不同的逻辑)
在C中是没有函数重载,当函数逻辑类似,但参数不同时就得不断的去找一些合适的函数名去定义。
函数重载,支持定义重名的函数。

C++函数重载:是根制函数参数中的参数类型,参数顺序,参数个数的不同,调用与之匹配的函数。
与返回值是没有关系。
重载函数的调用会根据类型的不同,自动推导该调用那个版本的函数。

编译器在编译的过程中,其实已经根据类型不同生成了不同名字的函数,只不过在C++层面上看到的名字是相同的。

#include <iostream>
using namespace std;

int add(int a,int b,int c)
{
    return a+b+c;
}
int add(int a,int b)
{
    return a+b;
}
int main()
{
    int a=10;
    int b=20;
    int c=30;
    cout << add(a,b) << endl;//结果是30
    cout << add(a,b,c) << endl;//结果是60
    return 0;
}

结果展示:
在这里插入图片描述

注:
一定要注意不要出现下面的用法,有歧义会报错

#include <iostream>
using namespace std;

int add(int a,int b,int c=10)
{
    return a+b+c;
}
int add(int a,int b)
{
    return a+b;
}
int main()
{
    int a=10;
    int b=20;
    int c=30;
    //cout << add(a,b) << endl;
    //有歧义会报错
    return 0;
}

六、哑元

在定义函数的时候,某个或某几个参数只有类型,没有参数名这个类型只起到一个占位的作用。
哑元一般在代码升级的过程中可能会用到。
如原本函数的实现需要3个参数,升级后发现只有两个就够了,此时只需要修改函数的定义,将不用的那个参数改成哑元就无须修改函数调用处了。
注意:虽然支持,但是一般不这样使用。
哑元的必须使用处:自增、自减运算符重载的时候,会用到哑元占位。

#include <iostream>
using namespace std;

int add(int a,int,int c=10)
{
    return a+c;
}

int main()
{
    int a=10;
    int b=20;
    int c=30;
    cout << add(a,b,c) << endl;//输出40
    return 0;
}

结果展示:
在这里插入图片描述

相关文章:

  • 期货行业首批信创试点单位转型实践|信创专题
  • Ambari升级Atlas1.1.0到2.2.0
  • 公众号搜题平台系统
  • 【PTHREAD】线程退出与取消
  • 组件命名报错 “Component name “XXX“ should always be multi-word”的解决方法
  • 离职前一定要删除这几个文件,不然你的微信聊天记录全被别人看了
  • Vue(模板语法1)
  • 银行利率bp是什么意思,bp是什么意思贷款利率
  • 暗月项目四
  • 目标检测——关键点检测学习记录(三):人体骨骼点检测——自底向上
  • 隐私计算+区块链原生融合之后平台开放、提升性能,蚂蚁链隐私协作平台FAIR重磅架构升级
  • Loki 收集Nginx日志以 grafana 可视化展示
  • 异常与错误处理高级用法
  • Java学习----Map接口
  • 设计模式-概述. 类图.软件设计原则详细讲解
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • 《Java编程思想》读书笔记-对象导论
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • JS专题之继承
  • spring学习第二天
  • 爬虫模拟登陆 SegmentFault
  • 普通函数和构造函数的区别
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 少走弯路,给Java 1~5 年程序员的建议
  • 学习Vue.js的五个小例子
  • 运行时添加log4j2的appender
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #pragma pack(1)
  • #stm32整理(一)flash读写
  • (145)光线追踪距离场柔和阴影
  • (2)Java 简介
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (vue)页面文件上传获取:action地址
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (五)关系数据库标准语言SQL
  • (原創) 系統分析和系統設計有什麼差別? (OO)
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • /bin、/sbin、/usr/bin、/usr/sbin
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [ HTML + CSS + Javascript ] 复盘尝试制作 2048 小游戏时遇到的问题
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [].shift.call( arguments ) 和 [].slice.call( arguments )
  • [20190113]四校联考
  • [AutoSAR 存储] 汽车智能座舱的存储需求
  • [AX]AX2012开发新特性-禁止表或者表字段
  • [BZOJ3223]文艺平衡树
  • [Bzoj4722]由乃(线段树好题)(倍增处理模数小快速幂)
  • [ESP32] 编码旋钮驱动
  • [IE技巧] 让IE 以全屏模式启动
  • [JavaEE] 线程与进程的区别详解
  • [javaSE] GUI(Action事件)
  • [LeetCode] Wildcard Matching