C++——基础

news2024/12/29 14:23:19

初学C++的时候,有没有想过,为什么C++支持重载,而C不支持重载呢??

其实,一个程序运行起来都要经过四步骤

  1. 预处理
  2. 编译
  3. 汇编
  4. 链接

预处理阶段会经过去注释,宏替换,头文件展开,条件编译... 

编译阶段会生成汇编代码,会经过语法分析,词法分析,语义分析,符号汇总...(像了解详细的可以去看看 《程序员的自我修养》,在它的第二章会详细讲解)


汇编阶段会将汇编生成二进制,然后在这一阶段生成符号表

链接阶段会合并段表,符号表的汇总和重定向。

  1. 实际的项目中,通常由多个头文件和源文件构成,然后通过编译链接,最后形成.o文件,如果为我们一个test.cpp调用了add.cpp中的add函数,在编译后链接前,.o的目标文件中没有add函数的地址,因为add函数是在add.cpp中的,所以add的函数在add.o中,那么怎么办呢??
  2. 链接阶段解决了这个问题,链接器看到了test.o调用了add.o中的add函数,但是没有add的地址,就会去add.o中的符号表中去找add的地址,然后链接到一起。
  3. 这时,链接器会通过函数名的修饰规则去找,而不同编译器的函数名修饰规则不一样。

这里用Linux中的gcc和g++来做例子:

这时回到我们一开始的问题,为什么C++支持重载呢???  就是因为通过C++可以通过函数名的修饰规则来区分,而C函数名修饰规则后,函数名都是一样的,所以不能重载。

 那么有一个问题,如果有两个函数,函数名一样,参数一样,但返回值不同,这是否能构成重载呢??
当然不能,因为编译器不能够通过返回值不同来判断是否构成重载。


引用:引用不是定义一个变量,而是给已存在变量取了一个别名,编译器不会另外开辟空间,而是和变量一起共用一个空间。

引用经常和指针来对比,而引用经常用来做返回值,这时因为用引用来做返回值,可以提高效率。

#include <iostream>
#include <time.h>
using namespace std;

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;
}

int main()
{
    TestReturnByRefOrValue();

    return 0;
}

但有一个很重要的区别就是

  1. 语法程度上,引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
  2. 底层上来讲,引用的底层就是指针来实现的。

 类的6个默认成员函数:

构造函数:构造函数是一个特殊的成员函数,需要注意的是构造函数的工作是初始化对象。

而默认构造函数有三种:

  1. 用户没有显示实现的时候,编译器自动生成
  2. 用户显示实现,但是一个参数都没有(无参构造函数)
  3. 用户显示实现,参数全部都有缺省值(全缺省构造函数)

ps:这三种默认构造函数不能同时存在。如果2 3 同时存在,那么当一个类时空类的时候,它调用的时候就会存在歧义。

特征如下:

  1. 函数名和类名相同
  2. 没有返回值
  3. 对象实例化的时候会自动调用构造函数
  4. 构造函数可以重载

在创建对象的时候,编译器会自动调用构造函数,给每个成员赋初值,这时每个成员都会去走初始化列表。

初始化列表:以一个冒号开始,接着是一个逗号分割的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式。

class A
{
    A()
    :_a(a)
    ,_b(b)
    {}

    private:
    int _a;
    int _b;
};

当然每个成员在初始化的时候只能初始化一次,但有三种必须放到初始化列表中

  1. const成员变量
  2. 引用成员变量
  3.  自定义类型成员(且该类没有默认的构造函数)

析构函数:与构造函数相反,析构函数是在对象销毁时自动调用析构函数,完成对对象中资源的清理工作。

特征如下:

  1. 析构函数要在类名的前面 + ~
  2. 无参数无返回值
  3. 一个函数只有一个析构函数,最好变成虚函数,这样形成多态的一个条件。

拷贝构造函数:只有单个参数,该参数是对本类型的引用,当一个已经存在的对象初始化创建一个新对象的时候,会自动调用拷贝构造函数。

特征如下:

  1. 拷贝构造函数是构造函数的一个重载
  2. 拷贝构造函数的参数必须是本类型的引用,如果不加引用,会无限递归调用拷贝构造函数,最终会造成栈溢出。

编译器默认生成的拷贝构造函数是值拷贝,在某些场景是不能使用的,所以需要我们去深拷贝。

C++11增加了两个默认的成员函数:

  1. 移动构造函数
  2. 移动赋值运算符重载

针对移动构造函数和移动赋值运算符重载有写特定的要求:

  • 如果你没有自己实现移动构造函数,且没有实现析构函数,拷贝构造、拷贝赋值重载中的任何一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现了移动构造,如果实现了就调用移动构造,如果没有实现就调用默认的移动构造。
  • 如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中
    的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内
    置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋
    值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造
    完全类似)

 赋值运算符重载:C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有返回值类型,函数名字以及参数列表,其返回值类型与普通的函数类型。

特征如下:

  1. 重载操作符必须有一个类类型参数
  2. 作为类成员函数,形参比操作数少1,这时因为第一个隐藏的参数是this指针
  3. .* sizeof :?  .  不能重载

我们来看一下string的赋值运算符重载,不难发现它的返回值是string&。

想一想为什么返回值会是引用呢??

  • 返回值如果是引用那么就是可以提高返回的效率,因为会少一次拷贝构造,有返回值是为了支持连续的赋值

参数是const T&,是因为这样可以支持左值或右值,传递引用也是为了提高效率。


explicit关键字:

构造函数不仅仅可以构造还可以初始化对象,对于单个参数或除第一个参数无默认值其余都有默认值的构造函数,还具有隐式类型的转换的作用。而explicit关键字的作用就是修饰构造函数,禁止构造函数去隐式类型的转换。


static成员:

用static修饰的成员变量叫做静态成员变量,用static修饰的成员函数,叫做静态成员函数。静态成员变量一定要在类外进行初始化。

class A
{

    static int _a;
};

int A::_a = 1;

特征如下:

  1.  静态成员为所有类对象所共享,存在放静态区
  2. 静态成员变量必须在类外进行初始化,定义的时候不用加上static,类中只是声明
  3. 类静态成员可以通过 类名::静态成员 或者 对象::静态成员 来访问
  4. 静态成员函数没有this指针,不能访问任何的非静态成员变量
  5. 静态成员也受类修饰符的影响,受public,protect,private访问限定符的限制

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SPSS曲线回归

前言&#xff1a; 本专栏参考教材为《SPSS22.0从入门到精通》&#xff0c;由于软件版本原因&#xff0c;部分内容有所改变&#xff0c;为适应软件版本的变化&#xff0c;特此创作此专栏便于大家学习。本专栏使用软件为&#xff1a;SPSS25.0 本专栏所有的数据文件请点击此链接下…

RabbitMQ的 五种工作模型

RabbitMQ 其实一共有六种工作模式&#xff1a; 简单模式&#xff08;Simple&#xff09;、工作队列模式&#xff08;Work Queue&#xff09;、 发布订阅模式&#xff08;Publish/Subscribe&#xff09;、路由模式&#xff08;Routing&#xff09;、通配符模式&#xff08;Topi…

快速入门安装及使用git与svn的区别常用命令

一、导言 1、什么是svn&#xff1f; SVN是Subversion的简称&#xff0c;是一个集中式版本控制系统。与Git不同&#xff0c;SVN没有分布式的特性。在SVN中&#xff0c;项目的代码仓库位于服务器上&#xff0c;团队成员通过向服务器提交和获取代码来实现版本控制。SVN记录了每个…

C语言-for循环入门代码

#include <stdio.h>int main() {int count;for (count 0; count < 10; count){printf("1\n");}system("pause");return 0; }1 1 1 1 1 1 1 1 1 1 请按任意键继续. . .灵活的for循环 死循环 while(1) {... }#include <stdio.h> int main(…

千帆SDK开源到GitHub,开发者可免费下载使用!

目录 一、SDK的优势 二、千帆SDK&#xff1a;快速落地LLM应用 三、如何快速上手千帆SDK 1、SDK快速启动 快速安装 平台鉴权 如何获取AK/SK 以“Chat 对话”为调用示例 2. SDK进阶指引 3. 通过Langchain接入千帆SDK 为什么选择Langchain 开源社区 千帆社区 好消息&…

Java11新增特性

前言 在前面的文章中&#xff0c;我们已经介绍了 Java9的新增特性 和 Java10的新增特性 ,下面我们书接上文&#xff0c;来介绍一下Java11的新增特性 版本简介 Java 11 是 Java 平台的最新版本&#xff0c;于2018年9月25日发布。这个版本是自Java 8以来最重要的更新之一&…

n-gram语言模型——句子概率分布计算与平滑

n-gram语言模型——句子概率分布计算与平滑 前言 语言模型 等价假设 n元语法 句子概率分布计算方式 数据平滑 Lidstone平滑(1-gram) Laplace平滑(1-gram) 附上两种平滑在1-gram下代码 Lidstone平滑与Laplace平滑(2-gram) 附上两种平滑在2-gram下代码 前言 语言模型…

隧道施工工艺流程vr线上虚拟展示成为产品3D说明书

行业内都知道&#xff0c;汽车生产的大部分都需要冲压加工来完成&#xff0c;因此汽车冲压工艺是汽车制造过程中的重要环节&#xff0c;传统的展示方式往往局限于二维图纸和实地操作&#xff0c;难以充分展现工艺的细节和流程。然而&#xff0c;随着技术的进步&#xff0c;汽车…

Java类和对象(续)

书接上回我们已经学完了对象的初始化&#xff0c;今天的内容更加精彩。 1.封装 面向对象程序的三大特征&#xff1a;封装&#xff0c;继承&#xff0c;多态。 本章主要也是要研究封装&#xff0c;简单来说就是套壳屏蔽细节。 封装的概念&#xff1a; 封装&#xff1a;将数据和…

【PWN · ret2csu】[HNCTF 2022 WEEK2]ret2csu

记一道ret2csu 一、题目 二、思路 1.ret2csu用write泄露write的真实地址->泄露libc->获得system的真实地址 2.ret2csu用read写/bin/sh字符串到bss段上 3.ret2csu用write将system的真实地址写到bss段上 4.ret2csu调用system 三、exp from pwn import * from pwn impo…

[100天算法】-最短无序连续子数组(day 70)

题目描述 给定一个整数数组&#xff0c;你需要寻找一个连续的子数组&#xff0c;如果对这个子数组进行升序排序&#xff0c;那么整个数组都会变为升序排序。你找到的子数组应是最短的&#xff0c;请输出它的长度。示例 1:输入: [2, 6, 4, 8, 10, 9, 15] 输出: 5 解释: 你只需要…

this和super

文章目录 this用法普通的直接引用区分形参与实参 super用法普通的直接引用区分子类与父类同名的属性或方法 this和super 与 构造方法总结 this this引用表示当前对象对象的引用。 用法 普通的直接引用 public class Test {int a ;int b;public Test() {this.b 0;} }调用当…

时间序列预测实战(十一)用SCINet实现滚动预测功能(附代码+数据集+原理介绍)

论文地址->SCINet官方论文地址 官方代码地址-> 官方代码下载地址 个人整理的代码地址->免费分享给大家创作不易请大家给文章点点赞 一、本文介绍 这篇文章给大家带来的是关于SCINet实现时间序列滚动预测功能的讲解&#xff0c;SCINet是样本卷积交换网络的缩写(Sam…

C# .NET Core API 注入Swagger

C# .NET Core API 注入Swagger 环境 Windows 10Visual Studio 2019(2017就有可以集中发布到publish目录的功能了吧)C#.NET Core 可跨平台发布代码,超级奈斯NuGet 套件管理dll将方法封装(据说可以提高效率,就像是我们用的dll那种感觉)Swagger 让接口可视化编写时间2020-12-09 …

【Python爬虫】网页抓取实例之淘宝商品信息抓取

之前我们已经说过网页抓取的相关内容 上次我们是以亚马逊某网页的产品为例 抓取价格、品牌、型号、样式等 该网页上价格、品牌、型号、样式等 都只有一个 如果网页上的目标内容 根据不同规格有多个 又该怎么提取呢&#xff1f; ▼如下图所示 当机身颜色、套餐、存储容量…

【MATLAB源码-第73期】基于matlab的OFDM-IM索引调制系统不同子载波数目误码率对比,对比OFDM系统。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 OFDM-IM索引调制技术是一种新型的无线通信技术&#xff0c;它将正交频分复用&#xff08;OFDM&#xff09;和索引调制&#xff08;IM&#xff09;相结合&#xff0c;以提高频谱效率和系统容量。OFDM-IM索引调制技术的基本思想…

ARM IMX6ULL 基础学习记录 / ARM 寄存器介绍

编辑整理 by Staok。 本文大部分内容摘自“100ask imx6ull”开发板的配套资料&#xff08;如《IMX6ULL裸机开发完全手册》等等&#xff09;&#xff0c;侵删。进行了精髓提取&#xff0c;方便日后查阅。过于基础的内容不会在此提及。如有错误恭谢指出&#xff01; 注&#xf…

Django ModelSerializer 实现自定义验证详解

随着 Web 开发的日益复杂化&#xff0c;对数据验证的需求也日益增加。Django REST framework 提供了一套强大的、灵活的验证系统&#xff0c;帮助开发者轻松处理各种复杂情况。本文将重点探讨 Django ModelSerializer 中如何实现自定义验证。 1. 简介 Django ModelSerializer…

openinstall携手途虎养车,赋能汽车服务数字化

近日&#xff0c;openinstall与中国领先的一站式汽车服务平台途虎养车再次续约&#xff0c;双方将开启第三年合作。过去两年&#xff0c;途虎在建设线上线下一体化数字平台的过程中&#xff0c;深度结合openinstall传参归因与渠道统计技术&#xff0c;打造出了一套高效的渠道来…

第12章 PyTorch图像分割代码框架-3:推理与部署

推理模块 模型训练完成后&#xff0c;需要单独再写一个推理模块来供用户测试或者使用&#xff0c;该模块可以命名为test.py或者inference.py&#xff0c;导入训练好的模型文件和待测试的图像&#xff0c;输出该图像的分割结果。inference.py主体部分如代码11-7所示。 代码11-7 …