c++基础2

一、c++的引用   引用和指针的的区别?

        引用是一种更安全的指针:

                1. 引用必须初始化,指针可以不用初始化
int a =10;
int *p; // 指针可能是野指针
int &b =a;

 //引用赋值",通常指的是直接修改引用所引用的对象的值,而不需要显式解引用。如果你在说 "指针赋值",通常需要通过解引用操作来修改指针所指向的对象的值。
                2. 引用只有一级引用,没有多级引用, 指针有一级,也有多级
int a =10;
int * p = &a;  // *p=30 需要手动解引用
int &b = a;   // 在底层 b =20; 的时候,会自动解引用
                3.  定义一个引用变量和 定义一个指针变量,其汇编指令是一样的; 通过引用变量修改所引用内存的值,和通过指针解引用修改指针指向内存的值,其底层指令也是一样的。
// 引用一个数组
int array[5] ={};
int (&q)[5] = array;

二、左值引用和右值引用 

        右值引用主要用于绑定到右值(右值是指表达式结束后不再存在的临时对象,比如字面量、临时表达式的结果等)。 

         左值引用和右值引用的引入是为了支持移动语义和避免不必要的拷贝操作,特别是在处理临时对象和资源管理时。右值引用可以绑定到临时对象,并通过移动语义实现高效的资源管理。左值引用则绑定到持久存在的对象,用于常规的引用传递和修改对象的操作。 C++11 引入了右值引用,C++14 进一步完善了右值引用的特性。

右值引用的本质主要体现在以下几个方面:

  1. 允许绑定到临时对象: 右值引用允许绑定到即将被销毁的临时对象,从而允许我们获取和操作这些临时对象的内容。

  2. 支持移动语义: 通过右值引用,可以实现移动语义。移动语义是一种在对象之间转移资源所有权的机制,可以避免不必要的拷贝操作,提高性能。

  3. 在重载函数中的应用: 右值引用广泛用于重载移动构造函数和移动赋值运算符,以实现高效的对象移动

  4. class MyString {
    public:
        // 移动构造函数
        MyString(MyString&& other) noexcept : data(other.data), size(other.size) {
            other.data = nullptr;
            other.size = 0;
        }
    
        // 移动赋值运算符
        MyString& operator=(MyString&& other) noexcept {
            if (this != &other) {
                delete[] data;
                data = other.data;
                size = other.size;
                other.data = nullptr;
                other.size = 0;
            }
            return *this;
        }
    
    private:
        char* data;
        std::size_t size;
    };
    

           上述代码中,MyString 类实现了移动构造函数和移动赋值运算符,通过右值引用,可以高效地进行对象的资源移动。

           总体而言,右值引用的本质是一种引用类型,其设计目的是为了支持移动语义和更高效的资源管理。通过右值引用,程序员可以更精准地控制对象的生命周期和资源的传递,以提高代码的性能和效率。

    三、 delete 和free区别是是吗?  new和malloc区别是什么?  

newmalloc 都是在 C++ 中用于动态分配内存的操作符,但它们有一些重要的区别:

  1. 语法:

    • new new 是 C++ 中的关键字,使用时直接调用,并返回指定类型的指针。
      int* p = new int;
    • malloc malloc 是 C 语言中的库函数,返回 void* 类型的指针。在 C++ 中可以使用,但通常搭配 reinterpret_cast 来进行类型转换。
      int* p = reinterpret_cast<int*>(malloc(sizeof(int)));
  2. 类型安全:

    • new new 是类型安全的,它会自动计算所需的内存大小,并返回指定类型的指针。它还调用了对象的构造函数,对于自定义类型来说更加方便。
    • malloc malloc 返回的是 void*,需要手动计算所需的内存大小,并且不会调用对象的构造函数。在 C++ 中,使用 malloc 分配内存后,需要使用 placement new 构造对象。
  3. 构造与析构:

    • new new 会调用对象的构造函数,创建一个完全初始化的对象。当使用 delete 释放内存时,会调用对象的析构函数。
    • malloc malloc 不会调用对象的构造函数和析构函数,需要手动管理对象的生命周期。
  4. 操作符重载:

    • new 可以通过重载 newdelete 操作符来自定义内存分配和释放行为。
    • malloc mallocfree 是标准库函数,不能被重载。
  5. 异常处理:

    • new 如果分配失败,会抛出 std::bad_alloc 异常,可以通过 nothrow 参数禁止抛出异常。
    • malloc 如果分配失败,返回 nullptr,不抛出异常。需要手动检查返回值。

在 C++ 中,推荐使用 newdelete,因为它们更加类型安全,对对象的构造和析构进行了正确处理。使用 mallocfree 主要是在一些特殊情况下,或者与 C 语言代码交互的场景中。在现代 C++ 中,智能指针和容器类的使用也减少了手动内存管理的需求

三、 面向对象

面向对象思想(详解)-CSDN博客

        面向对象是一种编程的思想,对象在栈上

类内实现的方法会自动展开为内联函数

类外实现的方法

对象的大小通过成员变量计算

#include <iostream>

class MyClass {
public:
    int x;  // 4 bytes
    char c; // 1 byte
    double d; // 8 bytes

    // Constructor
    MyClass(int a, char b, double e) : x(a), c(b), d(e) {}
};

int main() {
    std::cout << "Size of MyClass: " << sizeof(MyClass) << " bytes" << std::endl;
    return 0;
}

this 是一个指向当前对象的指针,它是类成员函数中的一个隐含参数。this 指针提供了对调用对象的访问,使得在类的成员函数中可以访问到当前对象的成员变量和其他成员函数。 

 每个对象都有自己的成员变量,但是他们共享一套成员方法。(那怎么区分哪个对象调用成员变量)

类的成员方法一经编译,所有的方法参数,都会加一个this指针,接受调用该方法的对象地址。this会告诉编译器处理哪个对象的方法。

以下是关于 this 指针的一些重要事项:

  1. 隐含参数: 在类的成员函数中,编译器会隐含地将当前对象的地址作为第一个参数传递给成员函数,而这个参数就是 this 指针。

  2. 使用 this 指针: 可以使用 this 指针访问对象的成员。例如,在成员函数中访问成员变量时,可以省略 this->,因为编译器会自动识别并添加。

    class MyClass {
    public:
        int x;
    
        void setX(int value) {
            this->x = value; // 可以省略this->,直接写成x = value
        }
    };
    
  3. 返回 this 指针: 在成员函数中,可以返回 this 指针,以支持链式调用(chaining)。使用链式调用可以写成:obj.setX(42).doSomething();

  4. class MyClass {
    public:
        int x;
    
        MyClass& setX(int value) {
            this->x = value;
            return *this;
        }
    };
    
  5. 在静态成员函数中不存在: 静态成员函数是与类关联而不是与对象关联的,因此在静态成员函数中不存在 this 指针。

    class MyClass {
    public:
        static void staticFunction() {
            // 在静态成员函数中无法使用this指针
        }
    };
    

this 指针在编写成员函数时非常有用,它使得成员函数能够访问对象的成员变量和其他成员函数。通过 this 指针,可以在类的成员函数中明确指出当前对象,从而正确地访问成员。

四、构造函数和析构函数

构造函数和析构函数的函数名字和类名一样,切没有返回值。

1 . 开辟内存(在栈上为对象开辟内存)

2. 调用构造函数(初始化,可以有参数,可以提供多个构造函数,叫做构造函数的重载)

...

n. 出作用域的时候,在return处对象依次会析构(先构造的晚析构,后构造的先析构, 类只能有一个析构函数,析构可以自己调用s1.~seq();,释放对象成员变量占用的外部堆内存, 析构函数调用以后,我们就说对象没有了,但是对象在栈上,只要函数存在对象就在,但是别去调用对象的方法,有可能造成堆的内存非法访问)

可以在三个地方创建对象:

栈(Stack)进入函数时构造

        
 深拷贝:

        在赋值时,把s2的new的内存直接丢了,而指向s1的。这时候需要做=运算符重载  s2.operator=(s1);

        深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)

        拷贝第一层级的对象属性或数组元素

        递归拷贝所有层级的对象属性和数组元素

        深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

  • 栈是一种后进先出(LIFO)的数据结构,用于存储函数调用和局部变量。
  • 对象在栈上分配的时候,它的生命周期与所在函数的生命周期相同,当函数执行完成时,对象自动被销毁。
  • 对象的大小通常较小,因为栈的大小是有限制的,过大的对象可能会导致栈溢出。
  • 通过在栈上分配对象,可以实现高效的内存管理,但是对象的生命周期受限于函数的执行。
    #include <iostream>
    
    class MyClass {
    public:
        MyClass(int val) : value(val) {
            std::cout << "Constructor called. Value: " << value << std::endl;
        }
    
        ~MyClass() {
            std::cout << "Destructor called. Value: " << value << std::endl;
        }
    
        void display() {
            std::cout << "Value: " << value << std::endl;
        }
    
    private:
        int value;
    };
    
    int main() {
        // 在栈上构建对象
        MyClass stackObject(10);
        stackObject.display();
    
        // 对象生命周期结束时,析构函数会被自动调用
        return 0;
    }
    

    堆(Heap) new的时候构造

  • 堆是一块用于动态分配内存的区域,对象在堆上分配时,它的生命周期由程序员负责管理。
  • 对象在堆上分配通常使用 new(C++)或 malloc(C)等操作符。
  • 使用堆分配内存可以实现灵活的对象生命周期,但需要手动释放分配的内存,以防止内存泄漏。
  • 堆上的对象可以在多个函数之间传递,因为它的生命周期不受限于单个函数
  • #include <iostream>
    
    class MyClass {
    public:
        MyClass(int val) : value(val) {
            std::cout << "Constructor called. Value: " << value << std::endl;
        }
    
        ~MyClass() {
            std::cout << "Destructor called. Value: " << value << std::endl;
        }
    
        void display() {
            std::cout << "Value: " << value << std::endl;
        }
    
    private:
        int value;
    };
    
    int main() {
        // 在堆上构建对象
        MyClass* heapObject = new MyClass(20);
        heapObject->display();
    
        // 注意:需要手动释放堆上分配的对象
        delete heapObject;
    
        return 0;
    }
    

    对于new的对象,是在堆上建的,首先delete会调用对象的析构函数对象在堆上的成员变量进行释放,然后再释放对象内存

  • 数据段/静态存储区程序启动时构造函数

  • 数据段用于存储全局变量和静态变量,这些变量在程序运行的整个生命周期内都存在。
  • 对象在数据段上分配时,它的生命周期与程序的生命周期相同。
  • 数据段适合存储一些在程序运行期间始终存在的全局数据。
    #include <iostream>
    
    class MyClass {
    public:
        MyClass(int val) : value(val) {
            std::cout << "Constructor called. Value: " << value << std::endl;
        }
    
        ~MyClass() {
            std::cout << "Destructor called. Value: " << value << std::endl;
        }
    
        void display() {
            std::cout << "Value: " << value << std::endl;
        }
    
    private:
        int value;
    };
    
    // 在数据段上定义全局对象
    MyClass globalObject(30);
    
    int main() {
        // 全局对象在整个程序生命周期内存在
        globalObject.display();
    
        return 0;
    }
    

  • 五、对象的深拷贝和浅拷贝

  •  浅拷贝

  • 浅拷贝只复制指向某个对象的指针,

    SeqStack s;
    SeqStack s1(10);
    SeqStack s2 =s1; // 默认拷贝构造函数 相当于 SeqStack s3(s1);   -》浅拷贝(内存拷贝)
    s2 =s1 ; 默认赋值函数  -》 浅拷贝(内存拷贝)
    点击并拖拽以移动
    memcpy和recalloc都是浅拷贝

    而不复制对象本身,新旧对象还是共享同一块内存(分支)

    浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。

    如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。

   深拷贝:

        在赋值时,把s2的new的内存直接丢了,而指向s1的。这时候需要做=运算符重载  s2.operator=(s1);

        深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)

        拷贝第一层级的对象属性或数组元素

        递归拷贝所有层级的对象属性和数组元素

        深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

 

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

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

相关文章

Three.JS教程1 环境搭建、场景与相机

Three.JS教程1 环境搭建、场景与相机 一、Three.JS简介二、环境搭建1. 开发准备2. 安装 three.js3. 新建文件index.htmlmain.js 4. 关于附加组件5. 启动 三、创建场景1. 场景的概念2. 相机的概念3. 相机的几个相关概念&#xff08;1&#xff09;视点&#xff08;Position&#…

信息登记小程序怎么做_重塑用户互动,开启全新营销篇章

信息登记小程序&#xff1a;重塑用户互动&#xff0c;开启全新营销篇章 在数字化浪潮中&#xff0c;小程序以其便捷、高效的特点&#xff0c;逐渐成为企业与用户之间沟通的桥梁。其中&#xff0c;信息登记小程序更是凭借其独特的定位&#xff0c;在众多小程序中脱颖而出。本文…

荣誉艾尔迪亚人的题解

目录 原题描述&#xff1a; 题目背景 题目描述 输入格式 输出格式 样例 Input 1 Output 1 Input 2 Output 2 数据范围&#xff1a; 样例解释 主要思路&#xff1a; 代码code&#xff1a; 原题描述&#xff1a; 时间限制: 1000ms 空间限制: 65536kb 题目背景 ​…

ros2 基础教程-使用ROS 2进行相机标定

ROS 2进行相机标定&#xff08;Camera Calibration&#xff09; 相机&#xff08;摄像头&#xff09;是一种非常精密的光学仪器&#xff0c;对外界环境的感知非常敏感。由于摄像头内部和外部的一些原因&#xff0c;摄像头采集的图像常常会发生一定的畸变。如果直接将采集到的图…

【分布式技术】ELK大型日志收集分析系统

目录 步骤一&#xff1a;完成JAVA环境部署 步骤二&#xff1a;部署ES节点&#xff08;三台主机&#xff09; 步骤三&#xff1a;内核参数修改 步骤四&#xff1a;web端查看验证 步骤五&#xff1a;yum安装nginx 步骤六&#xff1a;完成logstash部署 步骤七&#xff1a;部…

matlab抽取与插值

什么是抽取&#xff1f; 我们假设一个数字信号 x ( n ) , n 1 , 2 , . . . , N x(n),n1,2,...,N x(n),n1,2,...,N共有 N N N个点&#xff0c;抽取就是每个几个点抽1个点&#xff0c;比如2倍抽取&#xff0c;那么抽取后的信号为 y ( n ) , y ( 1 ) x ( 1 ) , y ( 2 ) x ( 3 …

stm32 FOC 电机介绍

今年开始学习foc控制无刷电机&#xff0c;这几天把所学整理一下&#xff0c;记录一下知识内容。 前言: 为什么要学习FOC? 1.电机控制是自动化控制领域重要一环。 2.目前直流无刷电机应用越来越广泛&#xff0c;如无人机、机械臂、云台、仿生机器人等等。 需要什么基础&…

项目管理十大知识领域之风险管理

1. 项目风险管理的定义与概述 项目风险管理是指为了实现项目目标&#xff0c;有计划地识别、评估和应对项目中的各种风险的过程。项目风险管理的核心在于提前辨识到可能对项目目标产生不利影响的不确定因素&#xff0c;并采取适当的措施降低或消除这些风险&#xff0c;以保障项…

three.js从入门到精通系列教程005 - three.js使用鼠标拖拽缩放浏览全景图

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>three.js从入门到精通系列教程005 - three.js使用鼠标拖拽缩放浏览全景图</title><script src"ThreeJS/three.js"></script><script src&qu…

基于SpringBoot Vue博物馆管理系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

深入数仓离线数据同步:问题分析与优化措施

一、前言 在数据仓库领域&#xff0c;离线数仓和实时数仓是常见的两种架构类型。离线数仓一般通过定时任务在特定时间点&#xff08;通常是凌晨&#xff09;将业务数据同步到数据仓库中。这种方式适用于对数据实时性要求不高&#xff0c;更侧重于历史数据分析和报告生成的场景…

Spring第六天(注解开发第三方Bean)

注解开发管理第三方Bean 显然&#xff0c;我们无法在第三方Bean中写入诸如service这样的注解&#xff0c;所以&#xff0c;Spring为我们提供了Bean这一注解来让我们通过注解管理第三方Bean 第二种导入方式由于可读性太低&#xff0c;故只介绍第一种导入方式&#xff0c;这里我…

【JavaEE】线程安全的集合类

作者主页&#xff1a;paper jie_博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文于《JavaEE》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精力)打造&…

【ARM Cortex-M 系列 1.1 -- Cortex-M33 与 M4 差异 详细介绍】

请阅读【嵌入式开发学习必备专栏 之 Cortex-Mx 专栏】 文章目录 背景Cortex-M33 与 M4 差异Cortex-M33Cortex-M4关系和差异举例说明 背景 在移植 RT-Thread 到 瑞萨RA4M2&#xff08;Cortex-M33&#xff09;上时&#xff0c;遇到了hardfault 问题&#xff0c;最后使用了Cortex…

路由器结构

路由器是连接互联网的设备&#xff0c;本文主要描述路由器的结构组成。 如上所示&#xff0c;OSI&#xff08;Open System Interconnect&#xff09;开放系统互联参考模型是互联网架构的标准协议栈&#xff0c;由ISO标准组织制定。自底向上&#xff0c;互联网架构分为7层&#…

行政快递管理软件使用教程

勤勤恳恳的行政人员&#xff0c;还在努力地修改企业快递管理制度&#xff0c;而聪明的行政人员&#xff0c;已经开始物色合适的快递管理软件了。随着企业管理的现代化发展&#xff0c;我们会发现很多管理模块都有相应的管理制度。人力资源管理、客户关系管理、财务管理等等&…

Unity animator动画倒放的方法

在Unity中&#xff0c; 我们有时候不仅需要animator正放的效果&#xff0c;也需要倒放的效果。但我们在实际制作动画的时候可以只制作一个正放的动画&#xff0c;然后通过代码控制倒放。 实现方法其实很简单&#xff0c;只需要把animator动画的speed设置为-1即为倒放&#xff…

MySQL中SELECT字句的顺序以及具体使用

目录 1.SELECT字句及其顺序 2.使用方法举例 3.HAVING和WHERE 1.SELECT字句及其顺序 *下表来自于图灵程序设计丛书&#xff0c;数据库系列——《SQL必知必会》 2.使用方法举例 *题目来源于牛客网 题目描述 现在运营想要查看不同大学的用户平均发帖情况&#xff0c;并期望结…

纯命令行在Ubuntu中安装qemu的ubuntu虚拟机,成功备忘

信息总体还算完整&#xff0c;有个别软件更新了名字&#xff0c;所以在这备忘一下 1. 验证kvm是否支持 ________________________________________________________________ $ grep vmx /proc/cpuinfo __________________________________________________________________…

【大数据】了解 YARN 架构的基础知识

了解 YARN 架构的基础知识 1.为什么是 YARN2.YARN 简介3.YARN 的组成部分3.1 Resource Manager 资源管理器3.1.1 Scheduler 调度程序3.1.2 Application Manager 应用程序管理器 3.2 Node Manager 节点管理器3.3 Application Master 应用程序主控3.4 Container 容器 4.在 YARN 中…